diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index e69de29..cd9bb89 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,7 @@ +# Learnlytics - in GoLang + +## Links + +- [Postgres as Auth](https://medium.com/@ValentinMouret/simple-authentication-with-only-postgresql-ff38f5bf8b0d) +- [templ](https://templ.guide/) +- [htmx](https://htmx.org/docs/#inheritance) diff --git a/assets/css/colors.css b/assets/css/colors.css new file mode 100644 index 0000000..79f3163 --- /dev/null +++ b/assets/css/colors.css @@ -0,0 +1,9 @@ +:root { + --text-color: #E0E1DD; + --text-color-inverted: #1f1e22; + --background-color: #0d1b2a; + --focused: #f4a260; + --unfocused: #2ec4b6; + --menu-bg: #1b3857; + --menu-border: #668580; +} diff --git a/assets/css/grid_layout.css b/assets/css/grid_layout.css new file mode 100644 index 0000000..3418761 --- /dev/null +++ b/assets/css/grid_layout.css @@ -0,0 +1,36 @@ +.two-split { + display: grid; + grid-template-columns: 1fr 4fr; + grid-auto-rows: 75px; +} + +.three-split { + display: grid; + grid-template-columns: 1fr 4fr 1fr; + grid-auto-rows: 75px; +} + +.grid-item-left { + display: flex; + align-items: center; + padding-left: 10%; + justify-content: left; +} + +.grid-item-center { + display: flex; + align-items: center; + justify-content: center; +} + +.one-row { + grid-template-rows: 1fr; +} + +.two-row { + grid-template-rows: 1fr 1fr; +} + +.three-row { + grid-template-rows: 1fr 1fr 1fr; +} diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 0000000..8138944 --- /dev/null +++ b/assets/css/style.css @@ -0,0 +1,319 @@ +@font-face { + font-family: "Lato"; + src: + url("/assets/fonts/lato/Lato-BlackItalic.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-Black.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-BoldItalic.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-Bold.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-Italic.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-LightItalic.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-Regular.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-ThinItalic.ttf") format("truetype"), + url("/assets/fonts/lato/Lato-Thin.ttf") format("truetype"); + font-weight: normal; + font-style: normal; +} + +.lato-thin { + font-family: "Lato", sans-serif; + font-weight: 100; + font-style: normal; +} + +.lato-light { + font-family: "Lato", sans-serif; + font-weight: 300; + font-style: normal; +} + +.lato-regular { + font-family: "Lato", sans-serif; + font-weight: 400; + font-style: normal; +} + +.lato-bold { + font-family: "Lato", sans-serif; + font-weight: 700; + font-style: normal; +} + +.lato-black { + font-family: "Lato", sans-serif; + font-weight: 900; + font-style: normal; +} + +.lato-thin-italic { + font-family: "Lato", sans-serif; + font-weight: 100; + font-style: italic; +} + +.lato-light-italic { + font-family: "Lato", sans-serif; + font-weight: 300; + font-style: italic; +} + +.lato-regular-italic { + font-family: "Lato", sans-serif; + font-weight: 400; + font-style: italic; +} + +.lato-bold-italic { + font-family: "Lato", sans-serif; + font-weight: 700; + font-style: italic; +} + +.lato-black-italic { + font-family: "Lato", sans-serif; + font-weight: 900; + font-style: italic; +} + +* { + color: var(--text-color); + font-family: lato-regular, sans-serif; + box-sizing: inherit; +} + +body { + background-color: var(--background-color); +} + +main { + position: absolute; + left: 50%; + transform: translate(-50%, 0%); + min-height: 110vh; + width: 90%; +} + +footer { + position: fixed; + left: 0; + bottom: 0; + background-color: var(--menu-bg); + width: 100vw; +} + +a { + color: var(--unfocused); + text-decoration: none; +} + +a:hover { + color: var(--focused); +} + +button { + color: var(--text-color-inverted); + background-color: var(--unfocused); + text-decoration: none; + border: none; +} + +button:hover { + color: var(--text-color); + background-color: var(--focused); +} + +.content_container { +} + + +.login { + zoom: 150%; + position: absolute; + top: 35%; + left: 50%; + transform: translate(-50%, -50%); + width: 40%; +} + +.login h1 { + font-size: 30px; + text-align: center; + margin-top: -20px; + margin-bottom: 1%; +} + +.login img { + position: relative; + left: 50%; + transform: translateX(-50%); +} + +.login form { + width: 100%; + text-align: center; +} + +.login input { + text-align: left; + font-size: 15px; + background-color: var(--background-color); + border: none; + border-bottom: 2px solid var(--unfocused); + transition: border-bottom 0.2s ease-out; +} + +.login input:focus { + outline: none; + border-bottom: 2px solid var(--focused); +} + +.login input:required { + border-bottom: 2px solid var(--focused); +} + +.login input[required]:invalid { + border-bottom: 2px solid var(--unfocused); +} + +.login input[type=text] { + background-image: url("/assets/img/id-card-negated.png"); + background-position: 5% center; + background-repeat: no-repeat; + background-size: 15px 15px; + text-indent: 15%; +} + +.login input[type=password] { + background-image: url("/assets/img/key-negated.png"); + background-position: 5% center; + background-repeat: no-repeat; + background-size: 15px 15px; + text-indent: 15%; +} + +.login input[type=submit] { + text-align: center; + width: 30%; + background-color: var(--background-color); + transition: border-bottom 0.2s ease-out; +} + +.login input[type=submit]:hover { + border-bottom: 2px solid var(--focused); +} + +.side_by_side { + display: flex; + justify-content: center; +} + +.error { + text-align: center; +} + +.error h1 { + font-size: 300%; +} + +.error h2 { + font-size: 200%; +} + +.error p { + font-size: 150%; + font-weight: bold; +} + +.navbar { + position: sticky; + top: 0; + width: 100%; + z-index: 1000; +} + +.navbar ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + background-color: var(--menu-bg); +} + +.navbar li { + float: left; + border-right: 1px solid var(--menu-border); +} + +.navbar li:first-child { + border-right: none; +} + +.navbar li:last-child { + float: right; + border-right: none; +} + +.navbar img { + object-fit: contain; + width: 80px; + margin: auto; +} + +.navbar a { + display: block; + padding: 8px; + font-size: 130%; + text-align: center; + color: var(--text-color-inverted); + background-color: var(--unfocused); +} + +.navbar a:hover { + color: var(--text-color); + background-color: var(--focused); +} + +.usercard { + border-radius: 10px; + border: 3px solid var(--unfocused); +} + +.usercard img { + display: block; + margin-top: 2%; + margin-bottom: 2%; + margin-left: auto; + margin-right: auto; + border-radius: 50%; + max-width: 70%; +} + +.usercard h1 { + margin-top: 0%; + text-align: center; + font-size: 150%; + background-color: var(--unfocused); + color: var(--text-color-inverted); +} + +.usercard p { + font-size: 90%; + font-weight: 700; +} + +.chart { + width: 50%; +} + +.button_row { + text-align: left; + padding-top: 1%; + padding-bottom: 1%; +} + +.button_row button { + font-size: 100%; + margin-left: 5%; + width: 15%; + border-radius: 4px; +} + diff --git a/assets/fonts/.gitignore b/assets/fonts/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/assets/fonts/lato/Lato-Black.ttf b/assets/fonts/lato/Lato-Black.ttf new file mode 100644 index 0000000..4340502 Binary files /dev/null and b/assets/fonts/lato/Lato-Black.ttf differ diff --git a/assets/fonts/lato/Lato-BlackItalic.ttf b/assets/fonts/lato/Lato-BlackItalic.ttf new file mode 100644 index 0000000..4df1555 Binary files /dev/null and b/assets/fonts/lato/Lato-BlackItalic.ttf differ diff --git a/assets/fonts/lato/Lato-Bold.ttf b/assets/fonts/lato/Lato-Bold.ttf new file mode 100644 index 0000000..016068b Binary files /dev/null and b/assets/fonts/lato/Lato-Bold.ttf differ diff --git a/assets/fonts/lato/Lato-BoldItalic.ttf b/assets/fonts/lato/Lato-BoldItalic.ttf new file mode 100644 index 0000000..a05d503 Binary files /dev/null and b/assets/fonts/lato/Lato-BoldItalic.ttf differ diff --git a/assets/fonts/lato/Lato-Italic.ttf b/assets/fonts/lato/Lato-Italic.ttf new file mode 100644 index 0000000..0d0f69e Binary files /dev/null and b/assets/fonts/lato/Lato-Italic.ttf differ diff --git a/assets/fonts/lato/Lato-Light.ttf b/assets/fonts/lato/Lato-Light.ttf new file mode 100644 index 0000000..dfa72ce Binary files /dev/null and b/assets/fonts/lato/Lato-Light.ttf differ diff --git a/assets/fonts/lato/Lato-LightItalic.ttf b/assets/fonts/lato/Lato-LightItalic.ttf new file mode 100644 index 0000000..12f2b6c Binary files /dev/null and b/assets/fonts/lato/Lato-LightItalic.ttf differ diff --git a/assets/fonts/lato/Lato-Regular.ttf b/assets/fonts/lato/Lato-Regular.ttf new file mode 100644 index 0000000..bb2e887 Binary files /dev/null and b/assets/fonts/lato/Lato-Regular.ttf differ diff --git a/assets/fonts/lato/Lato-Thin.ttf b/assets/fonts/lato/Lato-Thin.ttf new file mode 100644 index 0000000..ba58da1 Binary files /dev/null and b/assets/fonts/lato/Lato-Thin.ttf differ diff --git a/assets/fonts/lato/Lato-ThinItalic.ttf b/assets/fonts/lato/Lato-ThinItalic.ttf new file mode 100644 index 0000000..4d82766 Binary files /dev/null and b/assets/fonts/lato/Lato-ThinItalic.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Black.ttf b/assets/fonts/lato/MPLUSRounded1c-Black.ttf new file mode 100644 index 0000000..17c8974 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Black.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Bold.ttf b/assets/fonts/lato/MPLUSRounded1c-Bold.ttf new file mode 100644 index 0000000..c76efc5 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Bold.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-ExtraBold.ttf b/assets/fonts/lato/MPLUSRounded1c-ExtraBold.ttf new file mode 100644 index 0000000..263a885 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-ExtraBold.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Light.ttf b/assets/fonts/lato/MPLUSRounded1c-Light.ttf new file mode 100644 index 0000000..d150759 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Light.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Medium.ttf b/assets/fonts/lato/MPLUSRounded1c-Medium.ttf new file mode 100644 index 0000000..dc6ad66 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Medium.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Regular.ttf b/assets/fonts/lato/MPLUSRounded1c-Regular.ttf new file mode 100644 index 0000000..c8a6a55 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Regular.ttf differ diff --git a/assets/fonts/lato/MPLUSRounded1c-Thin.ttf b/assets/fonts/lato/MPLUSRounded1c-Thin.ttf new file mode 100644 index 0000000..7ae8486 Binary files /dev/null and b/assets/fonts/lato/MPLUSRounded1c-Thin.ttf differ diff --git a/assets/img/failed-exam.svg b/assets/img/failed-exam.svg new file mode 100644 index 0000000..25c731a --- /dev/null +++ b/assets/img/failed-exam.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/assets/img/icon/android-chrome-192x192.png b/assets/img/icon/android-chrome-192x192.png new file mode 100644 index 0000000..948eab8 Binary files /dev/null and b/assets/img/icon/android-chrome-192x192.png differ diff --git a/assets/img/icon/android-chrome-512x512.png b/assets/img/icon/android-chrome-512x512.png new file mode 100644 index 0000000..11aaa71 Binary files /dev/null and b/assets/img/icon/android-chrome-512x512.png differ diff --git a/assets/img/icon/apple-touch-icon.png b/assets/img/icon/apple-touch-icon.png new file mode 100644 index 0000000..655340c Binary files /dev/null and b/assets/img/icon/apple-touch-icon.png differ diff --git a/assets/img/icon/favicon-16x16.png b/assets/img/icon/favicon-16x16.png new file mode 100644 index 0000000..dec0a39 Binary files /dev/null and b/assets/img/icon/favicon-16x16.png differ diff --git a/assets/img/icon/favicon-32x32.png b/assets/img/icon/favicon-32x32.png new file mode 100644 index 0000000..b90845d Binary files /dev/null and b/assets/img/icon/favicon-32x32.png differ diff --git a/assets/img/icon/favicon.ico b/assets/img/icon/favicon.ico new file mode 100644 index 0000000..e540364 Binary files /dev/null and b/assets/img/icon/favicon.ico differ diff --git a/assets/img/icon/site.webmanifest b/assets/img/icon/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/assets/img/icon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/assets/img/id-card-negated.png b/assets/img/id-card-negated.png new file mode 100644 index 0000000..231f466 Binary files /dev/null and b/assets/img/id-card-negated.png differ diff --git a/assets/img/id-card.png b/assets/img/id-card.png new file mode 100644 index 0000000..94cc670 Binary files /dev/null and b/assets/img/id-card.png differ diff --git a/assets/img/key-negated.png b/assets/img/key-negated.png new file mode 100644 index 0000000..586aefd Binary files /dev/null and b/assets/img/key-negated.png differ diff --git a/assets/img/key.png b/assets/img/key.png new file mode 100644 index 0000000..263fe7f Binary files /dev/null and b/assets/img/key.png differ diff --git a/assets/img/learnlytics.png b/assets/img/learnlytics.png new file mode 100644 index 0000000..e43d877 Binary files /dev/null and b/assets/img/learnlytics.png differ diff --git a/assets/img/learnlytics.svg b/assets/img/learnlytics.svg new file mode 100644 index 0000000..a365086 --- /dev/null +++ b/assets/img/learnlytics.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/smiley-x.svg b/assets/img/smiley-x.svg new file mode 100644 index 0000000..25049f2 --- /dev/null +++ b/assets/img/smiley-x.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/img/user.jpeg b/assets/img/user.jpeg new file mode 100644 index 0000000..2575ca0 Binary files /dev/null and b/assets/img/user.jpeg differ diff --git a/assets/js/chart.js b/assets/js/chart.js new file mode 100644 index 0000000..9d6df8e --- /dev/null +++ b/assets/js/chart.js @@ -0,0 +1,20 @@ +/** + * Skipped minification because the original files appears to be already minified. + * Original file: /npm/chart.js@4.4.8/dist/chart.umd.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +/*! + * Chart.js v4.4.8 + * https://www.chartjs.org + * (c) 2025 Chart.js Contributors + * Released under the MIT License + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";var t=Object.freeze({__proto__:null,get Colors(){return Go},get Decimation(){return Qo},get Filler(){return ma},get Legend(){return ya},get SubTitle(){return ka},get Title(){return Ma},get Tooltip(){return Ba}});function e(){}const i=(()=>{let t=0;return()=>t++})();function s(t){return null==t}function n(t){if(Array.isArray&&Array.isArray(t))return!0;const e=Object.prototype.toString.call(t);return"[object"===e.slice(0,7)&&"Array]"===e.slice(-6)}function o(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}function a(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)}function r(t,e){return a(t)?t:e}function l(t,e){return void 0===t?e:t}const h=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100:+t/e,c=(t,e)=>"string"==typeof t&&t.endsWith("%")?parseFloat(t)/100*e:+t;function d(t,e,i){if(t&&"function"==typeof t.call)return t.apply(i,e)}function u(t,e,i,s){let a,r,l;if(n(t))if(r=t.length,s)for(a=r-1;a>=0;a--)e.call(i,t[a],a);else for(a=0;at,x:t=>t.x,y:t=>t.y};function v(t){const e=t.split("."),i=[];let s="";for(const t of e)s+=t,s.endsWith("\\")?s=s.slice(0,-1)+".":(i.push(s),s="");return i}function M(t,e){const i=y[e]||(y[e]=function(t){const e=v(t);return t=>{for(const i of e){if(""===i)break;t=t&&t[i]}return t}}(e));return i(t)}function w(t){return t.charAt(0).toUpperCase()+t.slice(1)}const k=t=>void 0!==t,S=t=>"function"==typeof t,P=(t,e)=>{if(t.size!==e.size)return!1;for(const i of t)if(!e.has(i))return!1;return!0};function D(t){return"mouseup"===t.type||"click"===t.type||"contextmenu"===t.type}const C=Math.PI,O=2*C,A=O+C,T=Number.POSITIVE_INFINITY,L=C/180,E=C/2,R=C/4,I=2*C/3,z=Math.log10,F=Math.sign;function V(t,e,i){return Math.abs(t-e)t-e)).pop(),e}function N(t){return!function(t){return"symbol"==typeof t||"object"==typeof t&&null!==t&&!(Symbol.toPrimitive in t||"toString"in t||"valueOf"in t)}(t)&&!isNaN(parseFloat(t))&&isFinite(t)}function H(t,e){const i=Math.round(t);return i-e<=t&&i+e>=t}function j(t,e,i){let s,n,o;for(s=0,n=t.length;sl&&h=Math.min(e,i)-s&&t<=Math.max(e,i)+s}function et(t,e,i){i=i||(i=>t[i]1;)s=o+n>>1,i(s)?o=s:n=s;return{lo:o,hi:n}}const it=(t,e,i,s)=>et(t,i,s?s=>{const n=t[s][e];return nt[s][e]et(t,i,(s=>t[s][e]>=i));function nt(t,e,i){let s=0,n=t.length;for(;ss&&t[n-1]>i;)n--;return s>0||n{const i="_onData"+w(e),s=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value(...e){const n=s.apply(this,e);return t._chartjs.listeners.forEach((t=>{"function"==typeof t[i]&&t[i](...e)})),n}})})))}function rt(t,e){const i=t._chartjs;if(!i)return;const s=i.listeners,n=s.indexOf(e);-1!==n&&s.splice(n,1),s.length>0||(ot.forEach((e=>{delete t[e]})),delete t._chartjs)}function lt(t){const e=new Set(t);return e.size===t.length?t:Array.from(e)}const ht="undefined"==typeof window?function(t){return t()}:window.requestAnimationFrame;function ct(t,e){let i=[],s=!1;return function(...n){i=n,s||(s=!0,ht.call(window,(()=>{s=!1,t.apply(e,i)})))}}function dt(t,e){let i;return function(...s){return e?(clearTimeout(i),i=setTimeout(t,e,s)):t.apply(this,s),e}}const ut=t=>"start"===t?"left":"end"===t?"right":"center",ft=(t,e,i)=>"start"===t?e:"end"===t?i:(e+i)/2,gt=(t,e,i,s)=>t===(s?"left":"right")?i:"center"===t?(e+i)/2:e;function pt(t,e,i){const n=e.length;let o=0,a=n;if(t._sorted){const{iScale:r,vScale:l,_parsed:h}=t,c=t.dataset&&t.dataset.options?t.dataset.options.spanGaps:null,d=r.axis,{min:u,max:f,minDefined:g,maxDefined:p}=r.getUserBounds();if(g){if(o=Math.min(it(h,d,u).lo,i?n:it(e,d,r.getPixelForValue(u)).lo),c){const t=h.slice(0,o+1).reverse().findIndex((t=>!s(t[l.axis])));o-=Math.max(0,t)}o=J(o,0,n-1)}if(p){let t=Math.max(it(h,r.axis,f,!0).hi+1,i?0:it(e,d,r.getPixelForValue(f),!0).hi+1);if(c){const e=h.slice(t-1).findIndex((t=>!s(t[l.axis])));t+=Math.max(0,e)}a=J(t,o,n)-o}else a=n-o}return{start:o,count:a}}function mt(t){const{xScale:e,yScale:i,_scaleRanges:s}=t,n={xmin:e.min,xmax:e.max,ymin:i.min,ymax:i.max};if(!s)return t._scaleRanges=n,!0;const o=s.xmin!==e.min||s.xmax!==e.max||s.ymin!==i.min||s.ymax!==i.max;return Object.assign(s,n),o}class xt{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(t,e,i,s){const n=e.listeners[s],o=e.duration;n.forEach((s=>s({chart:t,initial:e.initial,numSteps:o,currentStep:Math.min(i-e.start,o)})))}_refresh(){this._request||(this._running=!0,this._request=ht.call(window,(()=>{this._update(),this._request=null,this._running&&this._refresh()})))}_update(t=Date.now()){let e=0;this._charts.forEach(((i,s)=>{if(!i.running||!i.items.length)return;const n=i.items;let o,a=n.length-1,r=!1;for(;a>=0;--a)o=n[a],o._active?(o._total>i.duration&&(i.duration=o._total),o.tick(t),r=!0):(n[a]=n[n.length-1],n.pop());r&&(s.draw(),this._notify(s,i,t,"progress")),n.length||(i.running=!1,this._notify(s,i,t,"complete"),i.initial=!1),e+=n.length})),this._lastDate=t,0===e&&(this._running=!1)}_getAnims(t){const e=this._charts;let i=e.get(t);return i||(i={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},e.set(t,i)),i}listen(t,e,i){this._getAnims(t).listeners[e].push(i)}add(t,e){e&&e.length&&this._getAnims(t).items.push(...e)}has(t){return this._getAnims(t).items.length>0}start(t){const e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce(((t,e)=>Math.max(t,e._duration)),0),this._refresh())}running(t){if(!this._running)return!1;const e=this._charts.get(t);return!!(e&&e.running&&e.items.length)}stop(t){const e=this._charts.get(t);if(!e||!e.items.length)return;const i=e.items;let s=i.length-1;for(;s>=0;--s)i[s].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}remove(t){return this._charts.delete(t)}}var bt=new xt; +/*! + * @kurkle/color v0.3.2 + * https://github.com/kurkle/color#readme + * (c) 2023 Jukka Kurkela + * Released under the MIT License + */function _t(t){return t+.5|0}const yt=(t,e,i)=>Math.max(Math.min(t,i),e);function vt(t){return yt(_t(2.55*t),0,255)}function Mt(t){return yt(_t(255*t),0,255)}function wt(t){return yt(_t(t/2.55)/100,0,1)}function kt(t){return yt(_t(100*t),0,100)}const St={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Pt=[..."0123456789ABCDEF"],Dt=t=>Pt[15&t],Ct=t=>Pt[(240&t)>>4]+Pt[15&t],Ot=t=>(240&t)>>4==(15&t);function At(t){var e=(t=>Ot(t.r)&&Ot(t.g)&&Ot(t.b)&&Ot(t.a))(t)?Dt:Ct;return t?"#"+e(t.r)+e(t.g)+e(t.b)+((t,e)=>t<255?e(t):"")(t.a,e):void 0}const Tt=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Lt(t,e,i){const s=e*Math.min(i,1-i),n=(e,n=(e+t/30)%12)=>i-s*Math.max(Math.min(n-3,9-n,1),-1);return[n(0),n(8),n(4)]}function Et(t,e,i){const s=(s,n=(s+t/60)%6)=>i-i*e*Math.max(Math.min(n,4-n,1),0);return[s(5),s(3),s(1)]}function Rt(t,e,i){const s=Lt(t,1,.5);let n;for(e+i>1&&(n=1/(e+i),e*=n,i*=n),n=0;n<3;n++)s[n]*=1-e-i,s[n]+=e;return s}function It(t){const e=t.r/255,i=t.g/255,s=t.b/255,n=Math.max(e,i,s),o=Math.min(e,i,s),a=(n+o)/2;let r,l,h;return n!==o&&(h=n-o,l=a>.5?h/(2-n-o):h/(n+o),r=function(t,e,i,s,n){return t===n?(e-i)/s+(e>16&255,o>>8&255,255&o]}return t}(),Ht.transparent=[0,0,0,0]);const e=Ht[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}const $t=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;const Yt=t=>t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055,Ut=t=>t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4);function Xt(t,e,i){if(t){let s=It(t);s[e]=Math.max(0,Math.min(s[e]+s[e]*i,0===e?360:1)),s=Ft(s),t.r=s[0],t.g=s[1],t.b=s[2]}}function qt(t,e){return t?Object.assign(e||{},t):t}function Kt(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Mt(t[3]))):(e=qt(t,{r:0,g:0,b:0,a:1})).a=Mt(e.a),e}function Gt(t){return"r"===t.charAt(0)?function(t){const e=$t.exec(t);let i,s,n,o=255;if(e){if(e[7]!==i){const t=+e[7];o=e[8]?vt(t):yt(255*t,0,255)}return i=+e[1],s=+e[3],n=+e[5],i=255&(e[2]?vt(i):yt(i,0,255)),s=255&(e[4]?vt(s):yt(s,0,255)),n=255&(e[6]?vt(n):yt(n,0,255)),{r:i,g:s,b:n,a:o}}}(t):Bt(t)}class Zt{constructor(t){if(t instanceof Zt)return t;const e=typeof t;let i;var s,n,o;"object"===e?i=Kt(t):"string"===e&&(o=(s=t).length,"#"===s[0]&&(4===o||5===o?n={r:255&17*St[s[1]],g:255&17*St[s[2]],b:255&17*St[s[3]],a:5===o?17*St[s[4]]:255}:7!==o&&9!==o||(n={r:St[s[1]]<<4|St[s[2]],g:St[s[3]]<<4|St[s[4]],b:St[s[5]]<<4|St[s[6]],a:9===o?St[s[7]]<<4|St[s[8]]:255})),i=n||jt(t)||Gt(t)),this._rgb=i,this._valid=!!i}get valid(){return this._valid}get rgb(){var t=qt(this._rgb);return t&&(t.a=wt(t.a)),t}set rgb(t){this._rgb=Kt(t)}rgbString(){return this._valid?(t=this._rgb)&&(t.a<255?`rgba(${t.r}, ${t.g}, ${t.b}, ${wt(t.a)})`:`rgb(${t.r}, ${t.g}, ${t.b})`):void 0;var t}hexString(){return this._valid?At(this._rgb):void 0}hslString(){return this._valid?function(t){if(!t)return;const e=It(t),i=e[0],s=kt(e[1]),n=kt(e[2]);return t.a<255?`hsla(${i}, ${s}%, ${n}%, ${wt(t.a)})`:`hsl(${i}, ${s}%, ${n}%)`}(this._rgb):void 0}mix(t,e){if(t){const i=this.rgb,s=t.rgb;let n;const o=e===n?.5:e,a=2*o-1,r=i.a-s.a,l=((a*r==-1?a:(a+r)/(1+a*r))+1)/2;n=1-l,i.r=255&l*i.r+n*s.r+.5,i.g=255&l*i.g+n*s.g+.5,i.b=255&l*i.b+n*s.b+.5,i.a=o*i.a+(1-o)*s.a,this.rgb=i}return this}interpolate(t,e){return t&&(this._rgb=function(t,e,i){const s=Ut(wt(t.r)),n=Ut(wt(t.g)),o=Ut(wt(t.b));return{r:Mt(Yt(s+i*(Ut(wt(e.r))-s))),g:Mt(Yt(n+i*(Ut(wt(e.g))-n))),b:Mt(Yt(o+i*(Ut(wt(e.b))-o))),a:t.a+i*(e.a-t.a)}}(this._rgb,t._rgb,e)),this}clone(){return new Zt(this.rgb)}alpha(t){return this._rgb.a=Mt(t),this}clearer(t){return this._rgb.a*=1-t,this}greyscale(){const t=this._rgb,e=_t(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this}opaquer(t){return this._rgb.a*=1+t,this}negate(){const t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this}lighten(t){return Xt(this._rgb,2,t),this}darken(t){return Xt(this._rgb,2,-t),this}saturate(t){return Xt(this._rgb,1,t),this}desaturate(t){return Xt(this._rgb,1,-t),this}rotate(t){return function(t,e){var i=It(t);i[0]=Vt(i[0]+e),i=Ft(i),t.r=i[0],t.g=i[1],t.b=i[2]}(this._rgb,t),this}}function Jt(t){if(t&&"object"==typeof t){const e=t.toString();return"[object CanvasPattern]"===e||"[object CanvasGradient]"===e}return!1}function Qt(t){return Jt(t)?t:new Zt(t)}function te(t){return Jt(t)?t:new Zt(t).saturate(.5).darken(.1).hexString()}const ee=["x","y","borderWidth","radius","tension"],ie=["color","borderColor","backgroundColor"];const se=new Map;function ne(t,e,i){return function(t,e){e=e||{};const i=t+JSON.stringify(e);let s=se.get(i);return s||(s=new Intl.NumberFormat(t,e),se.set(i,s)),s}(e,i).format(t)}const oe={values:t=>n(t)?t:""+t,numeric(t,e,i){if(0===t)return"0";const s=this.chart.options.locale;let n,o=t;if(i.length>1){const e=Math.max(Math.abs(i[0].value),Math.abs(i[i.length-1].value));(e<1e-4||e>1e15)&&(n="scientific"),o=function(t,e){let i=e.length>3?e[2].value-e[1].value:e[1].value-e[0].value;Math.abs(i)>=1&&t!==Math.floor(t)&&(i=t-Math.floor(t));return i}(t,i)}const a=z(Math.abs(o)),r=isNaN(a)?1:Math.max(Math.min(-1*Math.floor(a),20),0),l={notation:n,minimumFractionDigits:r,maximumFractionDigits:r};return Object.assign(l,this.options.ticks.format),ne(t,s,l)},logarithmic(t,e,i){if(0===t)return"0";const s=i[e].significand||t/Math.pow(10,Math.floor(z(t)));return[1,2,3,5,10,15].includes(s)||e>.8*i.length?oe.numeric.call(this,t,e,i):""}};var ae={formatters:oe};const re=Object.create(null),le=Object.create(null);function he(t,e){if(!e)return t;const i=e.split(".");for(let e=0,s=i.length;et.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(t,e)=>te(e.backgroundColor),this.hoverBorderColor=(t,e)=>te(e.borderColor),this.hoverColor=(t,e)=>te(e.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(t),this.apply(e)}set(t,e){return ce(this,t,e)}get(t){return he(this,t)}describe(t,e){return ce(le,t,e)}override(t,e){return ce(re,t,e)}route(t,e,i,s){const n=he(this,t),a=he(this,i),r="_"+e;Object.defineProperties(n,{[r]:{value:n[e],writable:!0},[e]:{enumerable:!0,get(){const t=this[r],e=a[s];return o(t)?Object.assign({},e,t):l(t,e)},set(t){this[r]=t}}})}apply(t){t.forEach((t=>t(this)))}}var ue=new de({_scriptable:t=>!t.startsWith("on"),_indexable:t=>"events"!==t,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(t){t.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),t.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:t=>"onProgress"!==t&&"onComplete"!==t&&"fn"!==t}),t.set("animations",{colors:{type:"color",properties:ie},numbers:{type:"number",properties:ee}}),t.describe("animations",{_fallback:"animation"}),t.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:t=>0|t}}}})},function(t){t.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(t){t.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(t,e)=>e.lineWidth,tickColor:(t,e)=>e.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:ae.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),t.route("scale.ticks","color","","color"),t.route("scale.grid","color","","borderColor"),t.route("scale.border","color","","borderColor"),t.route("scale.title","color","","color"),t.describe("scale",{_fallback:!1,_scriptable:t=>!t.startsWith("before")&&!t.startsWith("after")&&"callback"!==t&&"parser"!==t,_indexable:t=>"borderDash"!==t&&"tickBorderDash"!==t&&"dash"!==t}),t.describe("scales",{_fallback:"scale"}),t.describe("scale.ticks",{_scriptable:t=>"backdropPadding"!==t&&"callback"!==t,_indexable:t=>"backdropPadding"!==t})}]);function fe(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ge(t){let e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e}function pe(t,e,i){let s;return"string"==typeof t?(s=parseInt(t,10),-1!==t.indexOf("%")&&(s=s/100*e.parentNode[i])):s=t,s}const me=t=>t.ownerDocument.defaultView.getComputedStyle(t,null);function xe(t,e){return me(t).getPropertyValue(e)}const be=["top","right","bottom","left"];function _e(t,e,i){const s={};i=i?"-"+i:"";for(let n=0;n<4;n++){const o=be[n];s[o]=parseFloat(t[e+"-"+o+i])||0}return s.width=s.left+s.right,s.height=s.top+s.bottom,s}const ye=(t,e,i)=>(t>0||e>0)&&(!i||!i.shadowRoot);function ve(t,e){if("native"in t)return t;const{canvas:i,currentDevicePixelRatio:s}=e,n=me(i),o="border-box"===n.boxSizing,a=_e(n,"padding"),r=_e(n,"border","width"),{x:l,y:h,box:c}=function(t,e){const i=t.touches,s=i&&i.length?i[0]:t,{offsetX:n,offsetY:o}=s;let a,r,l=!1;if(ye(n,o,t.target))a=n,r=o;else{const t=e.getBoundingClientRect();a=s.clientX-t.left,r=s.clientY-t.top,l=!0}return{x:a,y:r,box:l}}(t,i),d=a.left+(c&&r.left),u=a.top+(c&&r.top);let{width:f,height:g}=e;return o&&(f-=a.width+r.width,g-=a.height+r.height),{x:Math.round((l-d)/f*i.width/s),y:Math.round((h-u)/g*i.height/s)}}const Me=t=>Math.round(10*t)/10;function we(t,e,i,s){const n=me(t),o=_e(n,"margin"),a=pe(n.maxWidth,t,"clientWidth")||T,r=pe(n.maxHeight,t,"clientHeight")||T,l=function(t,e,i){let s,n;if(void 0===e||void 0===i){const o=t&&ge(t);if(o){const t=o.getBoundingClientRect(),a=me(o),r=_e(a,"border","width"),l=_e(a,"padding");e=t.width-l.width-r.width,i=t.height-l.height-r.height,s=pe(a.maxWidth,o,"clientWidth"),n=pe(a.maxHeight,o,"clientHeight")}else e=t.clientWidth,i=t.clientHeight}return{width:e,height:i,maxWidth:s||T,maxHeight:n||T}}(t,e,i);let{width:h,height:c}=l;if("content-box"===n.boxSizing){const t=_e(n,"border","width"),e=_e(n,"padding");h-=e.width+t.width,c-=e.height+t.height}h=Math.max(0,h-o.width),c=Math.max(0,s?h/s:c-o.height),h=Me(Math.min(h,a,l.maxWidth)),c=Me(Math.min(c,r,l.maxHeight)),h&&!c&&(c=Me(h/2));return(void 0!==e||void 0!==i)&&s&&l.height&&c>l.height&&(c=l.height,h=Me(Math.floor(c*s))),{width:h,height:c}}function ke(t,e,i){const s=e||1,n=Math.floor(t.height*s),o=Math.floor(t.width*s);t.height=Math.floor(t.height),t.width=Math.floor(t.width);const a=t.canvas;return a.style&&(i||!a.style.height&&!a.style.width)&&(a.style.height=`${t.height}px`,a.style.width=`${t.width}px`),(t.currentDevicePixelRatio!==s||a.height!==n||a.width!==o)&&(t.currentDevicePixelRatio=s,a.height=n,a.width=o,t.ctx.setTransform(s,0,0,s,0,0),!0)}const Se=function(){let t=!1;try{const e={get passive(){return t=!0,!1}};fe()&&(window.addEventListener("test",null,e),window.removeEventListener("test",null,e))}catch(t){}return t}();function Pe(t,e){const i=xe(t,e),s=i&&i.match(/^(\d+)(\.\d+)?px$/);return s?+s[1]:void 0}function De(t){return!t||s(t.size)||s(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}function Ce(t,e,i,s,n){let o=e[n];return o||(o=e[n]=t.measureText(n).width,i.push(n)),o>s&&(s=o),s}function Oe(t,e,i,s){let o=(s=s||{}).data=s.data||{},a=s.garbageCollect=s.garbageCollect||[];s.font!==e&&(o=s.data={},a=s.garbageCollect=[],s.font=e),t.save(),t.font=e;let r=0;const l=i.length;let h,c,d,u,f;for(h=0;hi.length){for(h=0;h0&&t.stroke()}}function Re(t,e,i){return i=i||.5,!e||t&&t.x>e.left-i&&t.xe.top-i&&t.y0&&""!==r.strokeColor;let c,d;for(t.save(),t.font=a.string,function(t,e){e.translation&&t.translate(e.translation[0],e.translation[1]),s(e.rotation)||t.rotate(e.rotation),e.color&&(t.fillStyle=e.color),e.textAlign&&(t.textAlign=e.textAlign),e.textBaseline&&(t.textBaseline=e.textBaseline)}(t,r),c=0;ct[0])){const o=i||t;void 0===s&&(s=ti("_fallback",t));const a={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:t,_rootScopes:o,_fallback:s,_getTarget:n,override:i=>je([i,...t],e,o,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete e._keys,delete t[0][i],!0),get:(i,s)=>qe(i,s,(()=>function(t,e,i,s){let n;for(const o of e)if(n=ti(Ue(o,t),i),void 0!==n)return Xe(t,n)?Je(i,s,t,n):n}(s,e,t,i))),getOwnPropertyDescriptor:(t,e)=>Reflect.getOwnPropertyDescriptor(t._scopes[0],e),getPrototypeOf:()=>Reflect.getPrototypeOf(t[0]),has:(t,e)=>ei(t).includes(e),ownKeys:t=>ei(t),set(t,e,i){const s=t._storage||(t._storage=n());return t[e]=s[e]=i,delete t._keys,!0}})}function $e(t,e,i,s){const a={_cacheable:!1,_proxy:t,_context:e,_subProxy:i,_stack:new Set,_descriptors:Ye(t,s),setContext:e=>$e(t,e,i,s),override:n=>$e(t.override(n),e,i,s)};return new Proxy(a,{deleteProperty:(e,i)=>(delete e[i],delete t[i],!0),get:(t,e,i)=>qe(t,e,(()=>function(t,e,i){const{_proxy:s,_context:a,_subProxy:r,_descriptors:l}=t;let h=s[e];S(h)&&l.isScriptable(e)&&(h=function(t,e,i,s){const{_proxy:n,_context:o,_subProxy:a,_stack:r}=i;if(r.has(t))throw new Error("Recursion detected: "+Array.from(r).join("->")+"->"+t);r.add(t);let l=e(o,a||s);r.delete(t),Xe(t,l)&&(l=Je(n._scopes,n,t,l));return l}(e,h,t,i));n(h)&&h.length&&(h=function(t,e,i,s){const{_proxy:n,_context:a,_subProxy:r,_descriptors:l}=i;if(void 0!==a.index&&s(t))return e[a.index%e.length];if(o(e[0])){const i=e,s=n._scopes.filter((t=>t!==i));e=[];for(const o of i){const i=Je(s,n,t,o);e.push($e(i,a,r&&r[t],l))}}return e}(e,h,t,l.isIndexable));Xe(e,h)&&(h=$e(h,a,r&&r[e],l));return h}(t,e,i))),getOwnPropertyDescriptor:(e,i)=>e._descriptors.allKeys?Reflect.has(t,i)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(t,i),getPrototypeOf:()=>Reflect.getPrototypeOf(t),has:(e,i)=>Reflect.has(t,i),ownKeys:()=>Reflect.ownKeys(t),set:(e,i,s)=>(t[i]=s,delete e[i],!0)})}function Ye(t,e={scriptable:!0,indexable:!0}){const{_scriptable:i=e.scriptable,_indexable:s=e.indexable,_allKeys:n=e.allKeys}=t;return{allKeys:n,scriptable:i,indexable:s,isScriptable:S(i)?i:()=>i,isIndexable:S(s)?s:()=>s}}const Ue=(t,e)=>t?t+w(e):e,Xe=(t,e)=>o(e)&&"adapters"!==t&&(null===Object.getPrototypeOf(e)||e.constructor===Object);function qe(t,e,i){if(Object.prototype.hasOwnProperty.call(t,e)||"constructor"===e)return t[e];const s=i();return t[e]=s,s}function Ke(t,e,i){return S(t)?t(e,i):t}const Ge=(t,e)=>!0===t?e:"string"==typeof t?M(e,t):void 0;function Ze(t,e,i,s,n){for(const o of e){const e=Ge(i,o);if(e){t.add(e);const o=Ke(e._fallback,i,n);if(void 0!==o&&o!==i&&o!==s)return o}else if(!1===e&&void 0!==s&&i!==s)return null}return!1}function Je(t,e,i,s){const a=e._rootScopes,r=Ke(e._fallback,i,s),l=[...t,...a],h=new Set;h.add(s);let c=Qe(h,l,i,r||i,s);return null!==c&&((void 0===r||r===i||(c=Qe(h,l,r,c,s),null!==c))&&je(Array.from(h),[""],a,r,(()=>function(t,e,i){const s=t._getTarget();e in s||(s[e]={});const a=s[e];if(n(a)&&o(i))return i;return a||{}}(e,i,s))))}function Qe(t,e,i,s,n){for(;i;)i=Ze(t,e,i,s,n);return i}function ti(t,e){for(const i of e){if(!i)continue;const e=i[t];if(void 0!==e)return e}}function ei(t){let e=t._keys;return e||(e=t._keys=function(t){const e=new Set;for(const i of t)for(const t of Object.keys(i).filter((t=>!t.startsWith("_"))))e.add(t);return Array.from(e)}(t._scopes)),e}function ii(t,e,i,s){const{iScale:n}=t,{key:o="r"}=this._parsing,a=new Array(s);let r,l,h,c;for(r=0,l=s;re"x"===t?"y":"x";function ai(t,e,i,s){const n=t.skip?e:t,o=e,a=i.skip?e:i,r=q(o,n),l=q(a,o);let h=r/(r+l),c=l/(r+l);h=isNaN(h)?0:h,c=isNaN(c)?0:c;const d=s*h,u=s*c;return{previous:{x:o.x-d*(a.x-n.x),y:o.y-d*(a.y-n.y)},next:{x:o.x+u*(a.x-n.x),y:o.y+u*(a.y-n.y)}}}function ri(t,e="x"){const i=oi(e),s=t.length,n=Array(s).fill(0),o=Array(s);let a,r,l,h=ni(t,0);for(a=0;a!t.skip))),"monotone"===e.cubicInterpolationMode)ri(t,n);else{let i=s?t[t.length-1]:t[0];for(o=0,a=t.length;o0===t||1===t,di=(t,e,i)=>-Math.pow(2,10*(t-=1))*Math.sin((t-e)*O/i),ui=(t,e,i)=>Math.pow(2,-10*t)*Math.sin((t-e)*O/i)+1,fi={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>-t*(t-2),easeInOutQuad:t=>(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1),easeInCubic:t=>t*t*t,easeOutCubic:t=>(t-=1)*t*t+1,easeInOutCubic:t=>(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2),easeInQuart:t=>t*t*t*t,easeOutQuart:t=>-((t-=1)*t*t*t-1),easeInOutQuart:t=>(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2),easeInQuint:t=>t*t*t*t*t,easeOutQuint:t=>(t-=1)*t*t*t*t+1,easeInOutQuint:t=>(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2),easeInSine:t=>1-Math.cos(t*E),easeOutSine:t=>Math.sin(t*E),easeInOutSine:t=>-.5*(Math.cos(C*t)-1),easeInExpo:t=>0===t?0:Math.pow(2,10*(t-1)),easeOutExpo:t=>1===t?1:1-Math.pow(2,-10*t),easeInOutExpo:t=>ci(t)?t:t<.5?.5*Math.pow(2,10*(2*t-1)):.5*(2-Math.pow(2,-10*(2*t-1))),easeInCirc:t=>t>=1?t:-(Math.sqrt(1-t*t)-1),easeOutCirc:t=>Math.sqrt(1-(t-=1)*t),easeInOutCirc:t=>(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1),easeInElastic:t=>ci(t)?t:di(t,.075,.3),easeOutElastic:t=>ci(t)?t:ui(t,.075,.3),easeInOutElastic(t){const e=.1125;return ci(t)?t:t<.5?.5*di(2*t,e,.45):.5+.5*ui(2*t-1,e,.45)},easeInBack(t){const e=1.70158;return t*t*((e+1)*t-e)},easeOutBack(t){const e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack(t){let e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:t=>1-fi.easeOutBounce(1-t),easeOutBounce(t){const e=7.5625,i=2.75;return t<1/i?e*t*t:t<2/i?e*(t-=1.5/i)*t+.75:t<2.5/i?e*(t-=2.25/i)*t+.9375:e*(t-=2.625/i)*t+.984375},easeInOutBounce:t=>t<.5?.5*fi.easeInBounce(2*t):.5*fi.easeOutBounce(2*t-1)+.5};function gi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:t.y+i*(e.y-t.y)}}function pi(t,e,i,s){return{x:t.x+i*(e.x-t.x),y:"middle"===s?i<.5?t.y:e.y:"after"===s?i<1?t.y:e.y:i>0?e.y:t.y}}function mi(t,e,i,s){const n={x:t.cp2x,y:t.cp2y},o={x:e.cp1x,y:e.cp1y},a=gi(t,n,i),r=gi(n,o,i),l=gi(o,e,i),h=gi(a,r,i),c=gi(r,l,i);return gi(h,c,i)}const xi=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,bi=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function _i(t,e){const i=(""+t).match(xi);if(!i||"normal"===i[1])return 1.2*e;switch(t=+i[2],i[3]){case"px":return t;case"%":t/=100}return e*t}const yi=t=>+t||0;function vi(t,e){const i={},s=o(e),n=s?Object.keys(e):e,a=o(t)?s?i=>l(t[i],t[e[i]]):e=>t[e]:()=>t;for(const t of n)i[t]=yi(a(t));return i}function Mi(t){return vi(t,{top:"y",right:"x",bottom:"y",left:"x"})}function wi(t){return vi(t,["topLeft","topRight","bottomLeft","bottomRight"])}function ki(t){const e=Mi(t);return e.width=e.left+e.right,e.height=e.top+e.bottom,e}function Si(t,e){t=t||{},e=e||ue.font;let i=l(t.size,e.size);"string"==typeof i&&(i=parseInt(i,10));let s=l(t.style,e.style);s&&!(""+s).match(bi)&&(console.warn('Invalid font style specified: "'+s+'"'),s=void 0);const n={family:l(t.family,e.family),lineHeight:_i(l(t.lineHeight,e.lineHeight),i),size:i,style:s,weight:l(t.weight,e.weight),string:""};return n.string=De(n),n}function Pi(t,e,i,s){let o,a,r,l=!0;for(o=0,a=t.length;oi&&0===t?0:t+e;return{min:a(s,-Math.abs(o)),max:a(n,o)}}function Ci(t,e){return Object.assign(Object.create(t),e)}function Oi(t,e,i){return t?function(t,e){return{x:i=>t+t+e-i,setWidth(t){e=t},textAlign:t=>"center"===t?t:"right"===t?"left":"right",xPlus:(t,e)=>t-e,leftForLtr:(t,e)=>t-e}}(e,i):{x:t=>t,setWidth(t){},textAlign:t=>t,xPlus:(t,e)=>t+e,leftForLtr:(t,e)=>t}}function Ai(t,e){let i,s;"ltr"!==e&&"rtl"!==e||(i=t.canvas.style,s=[i.getPropertyValue("direction"),i.getPropertyPriority("direction")],i.setProperty("direction",e,"important"),t.prevTextDirection=s)}function Ti(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Li(t){return"angle"===t?{between:Z,compare:K,normalize:G}:{between:tt,compare:(t,e)=>t-e,normalize:t=>t}}function Ei({start:t,end:e,count:i,loop:s,style:n}){return{start:t%i,end:e%i,loop:s&&(e-t+1)%i==0,style:n}}function Ri(t,e,i){if(!i)return[t];const{property:s,start:n,end:o}=i,a=e.length,{compare:r,between:l,normalize:h}=Li(s),{start:c,end:d,loop:u,style:f}=function(t,e,i){const{property:s,start:n,end:o}=i,{between:a,normalize:r}=Li(s),l=e.length;let h,c,{start:d,end:u,loop:f}=t;if(f){for(d+=l,u+=l,h=0,c=l;hb||l(n,x,p)&&0!==r(n,x),v=()=>!b||0===r(o,p)||l(o,x,p);for(let t=c,i=c;t<=d;++t)m=e[t%a],m.skip||(p=h(m[s]),p!==x&&(b=l(p,n,o),null===_&&y()&&(_=0===r(p,n)?t:i),null!==_&&v()&&(g.push(Ei({start:_,end:t,loop:u,count:a,style:f})),_=null),i=t,x=p));return null!==_&&g.push(Ei({start:_,end:d,loop:u,count:a,style:f})),g}function Ii(t,e){const i=[],s=t.segments;for(let n=0;nn&&t[o%e].skip;)o--;return o%=e,{start:n,end:o}}(i,n,o,s);if(!0===s)return Fi(t,[{start:a,end:r,loop:o}],i,e);return Fi(t,function(t,e,i,s){const n=t.length,o=[];let a,r=e,l=t[e];for(a=e+1;a<=i;++a){const i=t[a%n];i.skip||i.stop?l.skip||(s=!1,o.push({start:e%n,end:(a-1)%n,loop:s}),e=r=i.stop?a:null):(r=a,l.skip&&(e=a)),l=i}return null!==r&&o.push({start:e%n,end:r%n,loop:s}),o}(i,a,r!s(t[e.axis])));n.lo-=Math.max(0,a);const r=i.slice(n.hi).findIndex((t=>!s(t[e.axis])));n.hi+=Math.max(0,r)}return n}if(o._sharedOptions){const t=a[0],s="function"==typeof t.getRange&&t.getRange(e);if(s){const t=r(a,e,i-s),n=r(a,e,i+s);return{lo:t.lo,hi:n.hi}}}}return{lo:0,hi:a.length-1}}function Hi(t,e,i,s,n){const o=t.getSortedVisibleDatasetMetas(),a=i[e];for(let t=0,i=o.length;t{t[a]&&t[a](e[i],n)&&(o.push({element:t,datasetIndex:s,index:l}),r=r||t.inRange(e.x,e.y,n))})),s&&!r?[]:o}var Xi={evaluateInteractionItems:Hi,modes:{index(t,e,i,s){const n=ve(e,t),o=i.axis||"x",a=i.includeInvisible||!1,r=i.intersect?ji(t,n,o,s,a):Yi(t,n,o,!1,s,a),l=[];return r.length?(t.getSortedVisibleDatasetMetas().forEach((t=>{const e=r[0].index,i=t.data[e];i&&!i.skip&&l.push({element:i,datasetIndex:t.index,index:e})})),l):[]},dataset(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;let r=i.intersect?ji(t,n,o,s,a):Yi(t,n,o,!1,s,a);if(r.length>0){const e=r[0].datasetIndex,i=t.getDatasetMeta(e).data;r=[];for(let t=0;tji(t,ve(e,t),i.axis||"xy",s,i.includeInvisible||!1),nearest(t,e,i,s){const n=ve(e,t),o=i.axis||"xy",a=i.includeInvisible||!1;return Yi(t,n,o,i.intersect,s,a)},x:(t,e,i,s)=>Ui(t,ve(e,t),"x",i.intersect,s),y:(t,e,i,s)=>Ui(t,ve(e,t),"y",i.intersect,s)}};const qi=["left","top","right","bottom"];function Ki(t,e){return t.filter((t=>t.pos===e))}function Gi(t,e){return t.filter((t=>-1===qi.indexOf(t.pos)&&t.box.axis===e))}function Zi(t,e){return t.sort(((t,i)=>{const s=e?i:t,n=e?t:i;return s.weight===n.weight?s.index-n.index:s.weight-n.weight}))}function Ji(t,e){const i=function(t){const e={};for(const i of t){const{stack:t,pos:s,stackWeight:n}=i;if(!t||!qi.includes(s))continue;const o=e[t]||(e[t]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=n}return e}(t),{vBoxMaxWidth:s,hBoxMaxHeight:n}=e;let o,a,r;for(o=0,a=t.length;o{s[t]=Math.max(e[t],i[t])})),s}return s(t?["left","right"]:["top","bottom"])}function ss(t,e,i,s){const n=[];let o,a,r,l,h,c;for(o=0,a=t.length,h=0;ot.box.fullSize)),!0),s=Zi(Ki(e,"left"),!0),n=Zi(Ki(e,"right")),o=Zi(Ki(e,"top"),!0),a=Zi(Ki(e,"bottom")),r=Gi(e,"x"),l=Gi(e,"y");return{fullSize:i,leftAndTop:s.concat(o),rightAndBottom:n.concat(l).concat(a).concat(r),chartArea:Ki(e,"chartArea"),vertical:s.concat(n).concat(l),horizontal:o.concat(a).concat(r)}}(t.boxes),l=r.vertical,h=r.horizontal;u(t.boxes,(t=>{"function"==typeof t.beforeLayout&&t.beforeLayout()}));const c=l.reduce(((t,e)=>e.box.options&&!1===e.box.options.display?t:t+1),0)||1,d=Object.freeze({outerWidth:e,outerHeight:i,padding:n,availableWidth:o,availableHeight:a,vBoxMaxWidth:o/2/c,hBoxMaxHeight:a/2}),f=Object.assign({},n);ts(f,ki(s));const g=Object.assign({maxPadding:f,w:o,h:a,x:n.left,y:n.top},n),p=Ji(l.concat(h),d);ss(r.fullSize,g,d,p),ss(l,g,d,p),ss(h,g,d,p)&&ss(l,g,d,p),function(t){const e=t.maxPadding;function i(i){const s=Math.max(e[i]-t[i],0);return t[i]+=s,s}t.y+=i("top"),t.x+=i("left"),i("right"),i("bottom")}(g),os(r.leftAndTop,g,d,p),g.x+=g.w,g.y+=g.h,os(r.rightAndBottom,g,d,p),t.chartArea={left:g.left,top:g.top,right:g.left+g.w,bottom:g.top+g.h,height:g.h,width:g.w},u(r.chartArea,(e=>{const i=e.box;Object.assign(i,t.chartArea),i.update(g.w,g.h,{left:0,top:0,right:0,bottom:0})}))}};class rs{acquireContext(t,e){}releaseContext(t){return!1}addEventListener(t,e,i){}removeEventListener(t,e,i){}getDevicePixelRatio(){return 1}getMaximumSize(t,e,i,s){return e=Math.max(0,e||t.width),i=i||t.height,{width:e,height:Math.max(0,s?Math.floor(e/s):i)}}isAttached(t){return!0}updateConfig(t){}}class ls extends rs{acquireContext(t){return t&&t.getContext&&t.getContext("2d")||null}updateConfig(t){t.options.animation=!1}}const hs="$chartjs",cs={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},ds=t=>null===t||""===t;const us=!!Se&&{passive:!0};function fs(t,e,i){t&&t.canvas&&t.canvas.removeEventListener(e,i,us)}function gs(t,e){for(const i of t)if(i===e||i.contains(e))return!0}function ps(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||gs(i.addedNodes,s),e=e&&!gs(i.removedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}function ms(t,e,i){const s=t.canvas,n=new MutationObserver((t=>{let e=!1;for(const i of t)e=e||gs(i.removedNodes,s),e=e&&!gs(i.addedNodes,s);e&&i()}));return n.observe(document,{childList:!0,subtree:!0}),n}const xs=new Map;let bs=0;function _s(){const t=window.devicePixelRatio;t!==bs&&(bs=t,xs.forEach(((e,i)=>{i.currentDevicePixelRatio!==t&&e()})))}function ys(t,e,i){const s=t.canvas,n=s&&ge(s);if(!n)return;const o=ct(((t,e)=>{const s=n.clientWidth;i(t,e),s{const e=t[0],i=e.contentRect.width,s=e.contentRect.height;0===i&&0===s||o(i,s)}));return a.observe(n),function(t,e){xs.size||window.addEventListener("resize",_s),xs.set(t,e)}(t,o),a}function vs(t,e,i){i&&i.disconnect(),"resize"===e&&function(t){xs.delete(t),xs.size||window.removeEventListener("resize",_s)}(t)}function Ms(t,e,i){const s=t.canvas,n=ct((e=>{null!==t.ctx&&i(function(t,e){const i=cs[t.type]||t.type,{x:s,y:n}=ve(t,e);return{type:i,chart:e,native:t,x:void 0!==s?s:null,y:void 0!==n?n:null}}(e,t))}),t);return function(t,e,i){t&&t.addEventListener(e,i,us)}(s,e,n),n}class ws extends rs{acquireContext(t,e){const i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(function(t,e){const i=t.style,s=t.getAttribute("height"),n=t.getAttribute("width");if(t[hs]={initial:{height:s,width:n,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",i.boxSizing=i.boxSizing||"border-box",ds(n)){const e=Pe(t,"width");void 0!==e&&(t.width=e)}if(ds(s))if(""===t.style.height)t.height=t.width/(e||2);else{const e=Pe(t,"height");void 0!==e&&(t.height=e)}}(t,e),i):null}releaseContext(t){const e=t.canvas;if(!e[hs])return!1;const i=e[hs].initial;["height","width"].forEach((t=>{const n=i[t];s(n)?e.removeAttribute(t):e.setAttribute(t,n)}));const n=i.style||{};return Object.keys(n).forEach((t=>{e.style[t]=n[t]})),e.width=e.width,delete e[hs],!0}addEventListener(t,e,i){this.removeEventListener(t,e);const s=t.$proxies||(t.$proxies={}),n={attach:ps,detach:ms,resize:ys}[e]||Ms;s[e]=n(t,e,i)}removeEventListener(t,e){const i=t.$proxies||(t.$proxies={}),s=i[e];if(!s)return;({attach:vs,detach:vs,resize:vs}[e]||fs)(t,e,s),i[e]=void 0}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(t,e,i,s){return we(t,e,i,s)}isAttached(t){const e=t&&ge(t);return!(!e||!e.isConnected)}}function ks(t){return!fe()||"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas?ls:ws}var Ss=Object.freeze({__proto__:null,BasePlatform:rs,BasicPlatform:ls,DomPlatform:ws,_detectPlatform:ks});const Ps="transparent",Ds={boolean:(t,e,i)=>i>.5?e:t,color(t,e,i){const s=Qt(t||Ps),n=s.valid&&Qt(e||Ps);return n&&n.valid?n.mix(s,i).hexString():e},number:(t,e,i)=>t+(e-t)*i};class Cs{constructor(t,e,i,s){const n=e[i];s=Pi([t.to,s,n,t.from]);const o=Pi([t.from,n,s]);this._active=!0,this._fn=t.fn||Ds[t.type||typeof o],this._easing=fi[t.easing]||fi.linear,this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=this._total=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=i,this._from=o,this._to=s,this._promises=void 0}active(){return this._active}update(t,e,i){if(this._active){this._notify(!1);const s=this._target[this._prop],n=i-this._start,o=this._duration-n;this._start=i,this._duration=Math.floor(Math.max(o,t.duration)),this._total+=n,this._loop=!!t.loop,this._to=Pi([t.to,e,s,t.from]),this._from=Pi([t.from,s,e])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(t){const e=t-this._start,i=this._duration,s=this._prop,n=this._from,o=this._loop,a=this._to;let r;if(this._active=n!==a&&(o||e1?2-r:r,r=this._easing(Math.min(1,Math.max(0,r))),this._target[s]=this._fn(n,a,r))}wait(){const t=this._promises||(this._promises=[]);return new Promise(((e,i)=>{t.push({res:e,rej:i})}))}_notify(t){const e=t?"res":"rej",i=this._promises||[];for(let t=0;t{const a=t[s];if(!o(a))return;const r={};for(const t of e)r[t]=a[t];(n(a.properties)&&a.properties||[s]).forEach((t=>{t!==s&&i.has(t)||i.set(t,r)}))}))}_animateOptions(t,e){const i=e.options,s=function(t,e){if(!e)return;let i=t.options;if(!i)return void(t.options=e);i.$shared&&(t.options=i=Object.assign({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!s)return[];const n=this._createAnimations(s,i);return i.$shared&&function(t,e){const i=[],s=Object.keys(e);for(let e=0;e{t.options=i}),(()=>{})),n}_createAnimations(t,e){const i=this._properties,s=[],n=t.$animations||(t.$animations={}),o=Object.keys(e),a=Date.now();let r;for(r=o.length-1;r>=0;--r){const l=o[r];if("$"===l.charAt(0))continue;if("options"===l){s.push(...this._animateOptions(t,e));continue}const h=e[l];let c=n[l];const d=i.get(l);if(c){if(d&&c.active()){c.update(d,h,a);continue}c.cancel()}d&&d.duration?(n[l]=c=new Cs(d,t,l,h),s.push(c)):t[l]=h}return s}update(t,e){if(0===this._properties.size)return void Object.assign(t,e);const i=this._createAnimations(t,e);return i.length?(bt.add(this._chart,i),!0):void 0}}function As(t,e){const i=t&&t.options||{},s=i.reverse,n=void 0===i.min?e:0,o=void 0===i.max?e:0;return{start:s?o:n,end:s?n:o}}function Ts(t,e){const i=[],s=t._getSortedDatasetMetas(e);let n,o;for(n=0,o=s.length;n0||!i&&e<0)return n.index}return null}function zs(t,e){const{chart:i,_cachedMeta:s}=t,n=i._stacks||(i._stacks={}),{iScale:o,vScale:a,index:r}=s,l=o.axis,h=a.axis,c=function(t,e,i){return`${t.id}.${e.id}.${i.stack||i.type}`}(o,a,s),d=e.length;let u;for(let t=0;ti[t].axis===e)).shift()}function Vs(t,e){const i=t.controller.index,s=t.vScale&&t.vScale.axis;if(s){e=e||t._parsed;for(const t of e){const e=t._stacks;if(!e||void 0===e[s]||void 0===e[s][i])return;delete e[s][i],void 0!==e[s]._visualValues&&void 0!==e[s]._visualValues[i]&&delete e[s]._visualValues[i]}}}const Bs=t=>"reset"===t||"none"===t,Ws=(t,e)=>e?t:Object.assign({},t);class Ns{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(t,e){this.chart=t,this._ctx=t.ctx,this.index=e,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const t=this._cachedMeta;this.configure(),this.linkScales(),t._stacked=Es(t.vScale,t),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(t){this.index!==t&&Vs(this._cachedMeta),this.index=t}linkScales(){const t=this.chart,e=this._cachedMeta,i=this.getDataset(),s=(t,e,i,s)=>"x"===t?e:"r"===t?s:i,n=e.xAxisID=l(i.xAxisID,Fs(t,"x")),o=e.yAxisID=l(i.yAxisID,Fs(t,"y")),a=e.rAxisID=l(i.rAxisID,Fs(t,"r")),r=e.indexAxis,h=e.iAxisID=s(r,n,o,a),c=e.vAxisID=s(r,o,n,a);e.xScale=this.getScaleForId(n),e.yScale=this.getScaleForId(o),e.rScale=this.getScaleForId(a),e.iScale=this.getScaleForId(h),e.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(t){return this.chart.scales[t]}_getOtherScale(t){const e=this._cachedMeta;return t===e.iScale?e.vScale:e.iScale}reset(){this._update("reset")}_destroy(){const t=this._cachedMeta;this._data&&rt(this._data,this),t._stacked&&Vs(t)}_dataCheck(){const t=this.getDataset(),e=t.data||(t.data=[]),i=this._data;if(o(e)){const t=this._cachedMeta;this._data=function(t,e){const{iScale:i,vScale:s}=e,n="x"===i.axis?"x":"y",o="x"===s.axis?"x":"y",a=Object.keys(t),r=new Array(a.length);let l,h,c;for(l=0,h=a.length;l0&&i._parsed[t-1];if(!1===this._parsing)i._parsed=s,i._sorted=!0,d=s;else{d=n(s[t])?this.parseArrayData(i,s,t,e):o(s[t])?this.parseObjectData(i,s,t,e):this.parsePrimitiveData(i,s,t,e);const a=()=>null===c[l]||f&&c[l]t&&!e.hidden&&e._stacked&&{keys:Ts(i,!0),values:null})(e,i,this.chart),h={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(t){const{min:e,max:i,minDefined:s,maxDefined:n}=t.getUserBounds();return{min:s?e:Number.NEGATIVE_INFINITY,max:n?i:Number.POSITIVE_INFINITY}}(r);let u,f;function g(){f=s[u];const e=f[r.axis];return!a(f[t.axis])||c>e||d=0;--u)if(!g()){this.updateRangeFromParsed(h,t,f,l);break}return h}getAllParsedValues(t){const e=this._cachedMeta._parsed,i=[];let s,n,o;for(s=0,n=e.length;s=0&&tthis.getContext(i,s,e)),c);return f.$shared&&(f.$shared=r,n[o]=Object.freeze(Ws(f,r))),f}_resolveAnimations(t,e,i){const s=this.chart,n=this._cachedDataOpts,o=`animation-${e}`,a=n[o];if(a)return a;let r;if(!1!==s.options.animation){const s=this.chart.config,n=s.datasetAnimationScopeKeys(this._type,e),o=s.getOptionScopes(this.getDataset(),n);r=s.createResolver(o,this.getContext(t,i,e))}const l=new Os(s,r&&r.animations);return r&&r._cacheable&&(n[o]=Object.freeze(l)),l}getSharedOptions(t){if(t.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},t))}includeOptions(t,e){return!e||Bs(t)||this.chart._animationsDisabled}_getSharedOptions(t,e){const i=this.resolveDataElementOptions(t,e),s=this._sharedOptions,n=this.getSharedOptions(i),o=this.includeOptions(e,n)||n!==s;return this.updateSharedOptions(n,e,i),{sharedOptions:n,includeOptions:o}}updateElement(t,e,i,s){Bs(s)?Object.assign(t,i):this._resolveAnimations(e,s).update(t,i)}updateSharedOptions(t,e,i){t&&!Bs(e)&&this._resolveAnimations(void 0,e).update(t,i)}_setStyle(t,e,i,s){t.active=s;const n=this.getStyle(e,s);this._resolveAnimations(e,i,s).update(t,{options:!s&&this.getSharedOptions(n)||n})}removeHoverStyle(t,e,i){this._setStyle(t,i,"active",!1)}setHoverStyle(t,e,i){this._setStyle(t,i,"active",!0)}_removeDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!1)}_setDatasetHoverStyle(){const t=this._cachedMeta.dataset;t&&this._setStyle(t,void 0,"active",!0)}_resyncElements(t){const e=this._data,i=this._cachedMeta.data;for(const[t,e,i]of this._syncList)this[t](e,i);this._syncList=[];const s=i.length,n=e.length,o=Math.min(n,s);o&&this.parse(0,o),n>s?this._insertElements(s,n-s,t):n{for(t.length+=e,a=t.length-1;a>=o;a--)t[a]=t[a-e]};for(r(n),a=t;a{s[t]=i[t]&&i[t].active()?i[t]._to:this[t]})),s}}function js(t,e){const i=t.options.ticks,n=function(t){const e=t.options.offset,i=t._tickSize(),s=t._length/i+(e?0:1),n=t._maxLength/i;return Math.floor(Math.min(s,n))}(t),o=Math.min(i.maxTicksLimit||n,n),a=i.major.enabled?function(t){const e=[];let i,s;for(i=0,s=t.length;io)return function(t,e,i,s){let n,o=0,a=i[0];for(s=Math.ceil(s),n=0;nn)return e}return Math.max(n,1)}(a,e,o);if(r>0){let t,i;const n=r>1?Math.round((h-l)/(r-1)):null;for($s(e,c,d,s(n)?0:l-n,l),t=0,i=r-1;t"top"===e||"left"===e?t[e]+i:t[e]-i,Us=(t,e)=>Math.min(e||t,t);function Xs(t,e){const i=[],s=t.length/e,n=t.length;let o=0;for(;oa+r)))return h}function Ks(t){return t.drawTicks?t.tickLength:0}function Gs(t,e){if(!t.display)return 0;const i=Si(t.font,e),s=ki(t.padding);return(n(t.text)?t.text.length:1)*i.lineHeight+s.height}function Zs(t,e,i){let s=ut(t);return(i&&"right"!==e||!i&&"right"===e)&&(s=(t=>"left"===t?"right":"right"===t?"left":t)(s)),s}class Js extends Hs{constructor(t){super(),this.id=t.id,this.type=t.type,this.options=void 0,this.ctx=t.ctx,this.chart=t.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(t){this.options=t.setContext(this.getContext()),this.axis=t.axis,this._userMin=this.parse(t.min),this._userMax=this.parse(t.max),this._suggestedMin=this.parse(t.suggestedMin),this._suggestedMax=this.parse(t.suggestedMax)}parse(t,e){return t}getUserBounds(){let{_userMin:t,_userMax:e,_suggestedMin:i,_suggestedMax:s}=this;return t=r(t,Number.POSITIVE_INFINITY),e=r(e,Number.NEGATIVE_INFINITY),i=r(i,Number.POSITIVE_INFINITY),s=r(s,Number.NEGATIVE_INFINITY),{min:r(t,i),max:r(e,s),minDefined:a(t),maxDefined:a(e)}}getMinMax(t){let e,{min:i,max:s,minDefined:n,maxDefined:o}=this.getUserBounds();if(n&&o)return{min:i,max:s};const a=this.getMatchingVisibleMetas();for(let r=0,l=a.length;rs?s:i,s=n&&i>s?i:s,{min:r(i,r(s,i)),max:r(s,r(i,s))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels||[]}getLabelItems(t=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(t))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(t,e,i){const{beginAtZero:s,grace:n,ticks:o}=this.options,a=o.sampleSize;this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this._margins=i=Object.assign({left:0,right:0,top:0,bottom:0},i),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+i.left+i.right:this.height+i.top+i.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=Di(this,n,s),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const r=a=n||i<=1||!this.isHorizontal())return void(this.labelRotation=s);const h=this._getLabelSizes(),c=h.widest.width,d=h.highest.height,u=J(this.chart.width-c,0,this.maxWidth);o=t.offset?this.maxWidth/i:u/(i-1),c+6>o&&(o=u/(i-(t.offset?.5:1)),a=this.maxHeight-Ks(t.grid)-e.padding-Gs(t.title,this.chart.options.font),r=Math.sqrt(c*c+d*d),l=Y(Math.min(Math.asin(J((h.highest.height+6)/o,-1,1)),Math.asin(J(a/r,-1,1))-Math.asin(J(d/r,-1,1)))),l=Math.max(s,Math.min(n,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const t={width:0,height:0},{chart:e,options:{ticks:i,title:s,grid:n}}=this,o=this._isVisible(),a=this.isHorizontal();if(o){const o=Gs(s,e.options.font);if(a?(t.width=this.maxWidth,t.height=Ks(n)+o):(t.height=this.maxHeight,t.width=Ks(n)+o),i.display&&this.ticks.length){const{first:e,last:s,widest:n,highest:o}=this._getLabelSizes(),r=2*i.padding,l=$(this.labelRotation),h=Math.cos(l),c=Math.sin(l);if(a){const e=i.mirror?0:c*n.width+h*o.height;t.height=Math.min(this.maxHeight,t.height+e+r)}else{const e=i.mirror?0:h*n.width+c*o.height;t.width=Math.min(this.maxWidth,t.width+e+r)}this._calculatePadding(e,s,c,h)}}this._handleMargins(),a?(this.width=this._length=e.width-this._margins.left-this._margins.right,this.height=t.height):(this.width=t.width,this.height=this._length=e.height-this._margins.top-this._margins.bottom)}_calculatePadding(t,e,i,s){const{ticks:{align:n,padding:o},position:a}=this.options,r=0!==this.labelRotation,l="top"!==a&&"x"===this.axis;if(this.isHorizontal()){const a=this.getPixelForTick(0)-this.left,h=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;r?l?(c=s*t.width,d=i*e.height):(c=i*t.height,d=s*e.width):"start"===n?d=e.width:"end"===n?c=t.width:"inner"!==n&&(c=t.width/2,d=e.width/2),this.paddingLeft=Math.max((c-a+o)*this.width/(this.width-a),0),this.paddingRight=Math.max((d-h+o)*this.width/(this.width-h),0)}else{let i=e.height/2,s=t.height/2;"start"===n?(i=0,s=t.height):"end"===n&&(i=e.height,s=0),this.paddingTop=i+o,this.paddingBottom=s+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:t,position:e}=this.options;return"top"===e||"bottom"===e||"x"===t}isFullSize(){return this.options.fullSize}_convertTicksToLabels(t){let e,i;for(this.beforeTickToLabelConversion(),this.generateTickLabels(t),e=0,i=t.length;e{const i=t.gc,s=i.length/2;let n;if(s>e){for(n=0;n({width:r[t]||0,height:l[t]||0});return{first:P(0),last:P(e-1),widest:P(k),highest:P(S),widths:r,heights:l}}getLabelForValue(t){return t}getPixelForValue(t,e){return NaN}getValueForPixel(t){}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getPixelForDecimal(t){this._reversePixels&&(t=1-t);const e=this._startPixel+t*this._length;return Q(this._alignToPixels?Ae(this.chart,e,0):e)}getDecimalForPixel(t){const e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:t,max:e}=this;return t<0&&e<0?e:t>0&&e>0?t:0}getContext(t){const e=this.ticks||[];if(t>=0&&ta*s?a/i:r/s:r*s0}_computeGridLineItems(t){const e=this.axis,i=this.chart,s=this.options,{grid:n,position:a,border:r}=s,h=n.offset,c=this.isHorizontal(),d=this.ticks.length+(h?1:0),u=Ks(n),f=[],g=r.setContext(this.getContext()),p=g.display?g.width:0,m=p/2,x=function(t){return Ae(i,t,p)};let b,_,y,v,M,w,k,S,P,D,C,O;if("top"===a)b=x(this.bottom),w=this.bottom-u,S=b-m,D=x(t.top)+m,O=t.bottom;else if("bottom"===a)b=x(this.top),D=t.top,O=x(t.bottom)-m,w=b+m,S=this.top+u;else if("left"===a)b=x(this.right),M=this.right-u,k=b-m,P=x(t.left)+m,C=t.right;else if("right"===a)b=x(this.left),P=t.left,C=x(t.right)-m,M=b+m,k=this.left+u;else if("x"===e){if("center"===a)b=x((t.top+t.bottom)/2+.5);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}D=t.top,O=t.bottom,w=b+m,S=w+u}else if("y"===e){if("center"===a)b=x((t.left+t.right)/2);else if(o(a)){const t=Object.keys(a)[0],e=a[t];b=x(this.chart.scales[t].getPixelForValue(e))}M=b-m,k=M-u,P=t.left,C=t.right}const A=l(s.ticks.maxTicksLimit,d),T=Math.max(1,Math.ceil(d/A));for(_=0;_0&&(o-=s/2)}d={left:o,top:n,width:s+e.width,height:i+e.height,color:t.backdropColor}}x.push({label:v,font:P,textOffset:O,options:{rotation:m,color:i,strokeColor:o,strokeWidth:h,textAlign:f,textBaseline:A,translation:[M,w],backdrop:d}})}return x}_getXAxisLabelAlignment(){const{position:t,ticks:e}=this.options;if(-$(this.labelRotation))return"top"===t?"left":"right";let i="center";return"start"===e.align?i="left":"end"===e.align?i="right":"inner"===e.align&&(i="inner"),i}_getYAxisLabelAlignment(t){const{position:e,ticks:{crossAlign:i,mirror:s,padding:n}}=this.options,o=t+n,a=this._getLabelSizes().widest.width;let r,l;return"left"===e?s?(l=this.right+n,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l+=a)):(l=this.right-o,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l=this.left)):"right"===e?s?(l=this.left+n,"near"===i?r="right":"center"===i?(r="center",l-=a/2):(r="left",l-=a)):(l=this.left+o,"near"===i?r="left":"center"===i?(r="center",l+=a/2):(r="right",l=this.right)):r="right",{textAlign:r,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const t=this.chart,e=this.options.position;return"left"===e||"right"===e?{top:0,left:this.left,bottom:t.height,right:this.right}:"top"===e||"bottom"===e?{top:this.top,left:0,bottom:this.bottom,right:t.width}:void 0}drawBackground(){const{ctx:t,options:{backgroundColor:e},left:i,top:s,width:n,height:o}=this;e&&(t.save(),t.fillStyle=e,t.fillRect(i,s,n,o),t.restore())}getLineWidthForValue(t){const e=this.options.grid;if(!this._isVisible()||!e.display)return 0;const i=this.ticks.findIndex((e=>e.value===t));if(i>=0){return e.setContext(this.getContext(i)).lineWidth}return 0}drawGrid(t){const e=this.options.grid,i=this.ctx,s=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(t));let n,o;const a=(t,e,s)=>{s.width&&s.color&&(i.save(),i.lineWidth=s.width,i.strokeStyle=s.color,i.setLineDash(s.borderDash||[]),i.lineDashOffset=s.borderDashOffset,i.beginPath(),i.moveTo(t.x,t.y),i.lineTo(e.x,e.y),i.stroke(),i.restore())};if(e.display)for(n=0,o=s.length;n{this.drawBackground(),this.drawGrid(t),this.drawTitle()}},{z:s,draw:()=>{this.drawBorder()}},{z:e,draw:t=>{this.drawLabels(t)}}]:[{z:e,draw:t=>{this.draw(t)}}]}getMatchingVisibleMetas(t){const e=this.chart.getSortedVisibleDatasetMetas(),i=this.axis+"AxisID",s=[];let n,o;for(n=0,o=e.length;n{const s=i.split("."),n=s.pop(),o=[t].concat(s).join("."),a=e[i].split("."),r=a.pop(),l=a.join(".");ue.route(o,n,l,r)}))}(e,t.defaultRoutes);t.descriptors&&ue.describe(e,t.descriptors)}(t,o,i),this.override&&ue.override(t.id,t.overrides)),o}get(t){return this.items[t]}unregister(t){const e=this.items,i=t.id,s=this.scope;i in e&&delete e[i],s&&i in ue[s]&&(delete ue[s][i],this.override&&delete re[i])}}class tn{constructor(){this.controllers=new Qs(Ns,"datasets",!0),this.elements=new Qs(Hs,"elements"),this.plugins=new Qs(Object,"plugins"),this.scales=new Qs(Js,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...t){this._each("register",t)}remove(...t){this._each("unregister",t)}addControllers(...t){this._each("register",t,this.controllers)}addElements(...t){this._each("register",t,this.elements)}addPlugins(...t){this._each("register",t,this.plugins)}addScales(...t){this._each("register",t,this.scales)}getController(t){return this._get(t,this.controllers,"controller")}getElement(t){return this._get(t,this.elements,"element")}getPlugin(t){return this._get(t,this.plugins,"plugin")}getScale(t){return this._get(t,this.scales,"scale")}removeControllers(...t){this._each("unregister",t,this.controllers)}removeElements(...t){this._each("unregister",t,this.elements)}removePlugins(...t){this._each("unregister",t,this.plugins)}removeScales(...t){this._each("unregister",t,this.scales)}_each(t,e,i){[...e].forEach((e=>{const s=i||this._getRegistryForType(e);i||s.isForType(e)||s===this.plugins&&e.id?this._exec(t,s,e):u(e,(e=>{const s=i||this._getRegistryForType(e);this._exec(t,s,e)}))}))}_exec(t,e,i){const s=w(t);d(i["before"+s],[],i),e[t](i),d(i["after"+s],[],i)}_getRegistryForType(t){for(let e=0;et.filter((t=>!e.some((e=>t.plugin.id===e.plugin.id))));this._notify(s(e,i),t,"stop"),this._notify(s(i,e),t,"start")}}function nn(t,e){return e||!1!==t?!0===t?{}:t:null}function on(t,{plugin:e,local:i},s,n){const o=t.pluginScopeKeys(e),a=t.getOptionScopes(s,o);return i&&e.defaults&&a.push(e.defaults),t.createResolver(a,n,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function an(t,e){const i=ue.datasets[t]||{};return((e.datasets||{})[t]||{}).indexAxis||e.indexAxis||i.indexAxis||"x"}function rn(t){if("x"===t||"y"===t||"r"===t)return t}function ln(t,...e){if(rn(t))return t;for(const s of e){const e=s.axis||("top"===(i=s.position)||"bottom"===i?"x":"left"===i||"right"===i?"y":void 0)||t.length>1&&rn(t[0].toLowerCase());if(e)return e}var i;throw new Error(`Cannot determine type of '${t}' axis. Please provide 'axis' or 'position' option.`)}function hn(t,e,i){if(i[e+"AxisID"]===t)return{axis:e}}function cn(t,e){const i=re[t.type]||{scales:{}},s=e.scales||{},n=an(t.type,e),a=Object.create(null);return Object.keys(s).forEach((e=>{const r=s[e];if(!o(r))return console.error(`Invalid scale configuration for scale: ${e}`);if(r._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${e}`);const l=ln(e,r,function(t,e){if(e.data&&e.data.datasets){const i=e.data.datasets.filter((e=>e.xAxisID===t||e.yAxisID===t));if(i.length)return hn(t,"x",i[0])||hn(t,"y",i[0])}return{}}(e,t),ue.scales[r.type]),h=function(t,e){return t===e?"_index_":"_value_"}(l,n),c=i.scales||{};a[e]=b(Object.create(null),[{axis:l},r,c[l],c[h]])})),t.data.datasets.forEach((i=>{const n=i.type||t.type,o=i.indexAxis||an(n,e),r=(re[n]||{}).scales||{};Object.keys(r).forEach((t=>{const e=function(t,e){let i=t;return"_index_"===t?i=e:"_value_"===t&&(i="x"===e?"y":"x"),i}(t,o),n=i[e+"AxisID"]||e;a[n]=a[n]||Object.create(null),b(a[n],[{axis:e},s[n],r[t]])}))})),Object.keys(a).forEach((t=>{const e=a[t];b(e,[ue.scales[e.type],ue.scale])})),a}function dn(t){const e=t.options||(t.options={});e.plugins=l(e.plugins,{}),e.scales=cn(t,e)}function un(t){return(t=t||{}).datasets=t.datasets||[],t.labels=t.labels||[],t}const fn=new Map,gn=new Set;function pn(t,e){let i=fn.get(t);return i||(i=e(),fn.set(t,i),gn.add(i)),i}const mn=(t,e,i)=>{const s=M(e,i);void 0!==s&&t.add(s)};class xn{constructor(t){this._config=function(t){return(t=t||{}).data=un(t.data),dn(t),t}(t),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(t){this._config.type=t}get data(){return this._config.data}set data(t){this._config.data=un(t)}get options(){return this._config.options}set options(t){this._config.options=t}get plugins(){return this._config.plugins}update(){const t=this._config;this.clearCache(),dn(t)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(t){return pn(t,(()=>[[`datasets.${t}`,""]]))}datasetAnimationScopeKeys(t,e){return pn(`${t}.transition.${e}`,(()=>[[`datasets.${t}.transitions.${e}`,`transitions.${e}`],[`datasets.${t}`,""]]))}datasetElementScopeKeys(t,e){return pn(`${t}-${e}`,(()=>[[`datasets.${t}.elements.${e}`,`datasets.${t}`,`elements.${e}`,""]]))}pluginScopeKeys(t){const e=t.id;return pn(`${this.type}-plugin-${e}`,(()=>[[`plugins.${e}`,...t.additionalOptionScopes||[]]]))}_cachedScopes(t,e){const i=this._scopeCache;let s=i.get(t);return s&&!e||(s=new Map,i.set(t,s)),s}getOptionScopes(t,e,i){const{options:s,type:n}=this,o=this._cachedScopes(t,i),a=o.get(e);if(a)return a;const r=new Set;e.forEach((e=>{t&&(r.add(t),e.forEach((e=>mn(r,t,e)))),e.forEach((t=>mn(r,s,t))),e.forEach((t=>mn(r,re[n]||{},t))),e.forEach((t=>mn(r,ue,t))),e.forEach((t=>mn(r,le,t)))}));const l=Array.from(r);return 0===l.length&&l.push(Object.create(null)),gn.has(e)&&o.set(e,l),l}chartOptionScopes(){const{options:t,type:e}=this;return[t,re[e]||{},ue.datasets[e]||{},{type:e},ue,le]}resolveNamedOptions(t,e,i,s=[""]){const o={$shared:!0},{resolver:a,subPrefixes:r}=bn(this._resolverCache,t,s);let l=a;if(function(t,e){const{isScriptable:i,isIndexable:s}=Ye(t);for(const o of e){const e=i(o),a=s(o),r=(a||e)&&t[o];if(e&&(S(r)||_n(r))||a&&n(r))return!0}return!1}(a,e)){o.$shared=!1;l=$e(a,i=S(i)?i():i,this.createResolver(t,i,r))}for(const t of e)o[t]=l[t];return o}createResolver(t,e,i=[""],s){const{resolver:n}=bn(this._resolverCache,t,i);return o(e)?$e(n,e,void 0,s):n}}function bn(t,e,i){let s=t.get(e);s||(s=new Map,t.set(e,s));const n=i.join();let o=s.get(n);if(!o){o={resolver:je(e,i),subPrefixes:i.filter((t=>!t.toLowerCase().includes("hover")))},s.set(n,o)}return o}const _n=t=>o(t)&&Object.getOwnPropertyNames(t).some((e=>S(t[e])));const yn=["top","bottom","left","right","chartArea"];function vn(t,e){return"top"===t||"bottom"===t||-1===yn.indexOf(t)&&"x"===e}function Mn(t,e){return function(i,s){return i[t]===s[t]?i[e]-s[e]:i[t]-s[t]}}function wn(t){const e=t.chart,i=e.options.animation;e.notifyPlugins("afterRender"),d(i&&i.onComplete,[t],e)}function kn(t){const e=t.chart,i=e.options.animation;d(i&&i.onProgress,[t],e)}function Sn(t){return fe()&&"string"==typeof t?t=document.getElementById(t):t&&t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas),t}const Pn={},Dn=t=>{const e=Sn(t);return Object.values(Pn).filter((t=>t.canvas===e)).pop()};function Cn(t,e,i){const s=Object.keys(t);for(const n of s){const s=+n;if(s>=e){const o=t[n];delete t[n],(i>0||s>e)&&(t[s+i]=o)}}}function On(t,e,i){return t.options.clip?t[i]:e[i]}class An{static defaults=ue;static instances=Pn;static overrides=re;static registry=en;static version="4.4.8";static getChart=Dn;static register(...t){en.add(...t),Tn()}static unregister(...t){en.remove(...t),Tn()}constructor(t,e){const s=this.config=new xn(e),n=Sn(t),o=Dn(n);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const a=s.createResolver(s.chartOptionScopes(),this.getContext());this.platform=new(s.platform||ks(n)),this.platform.updateConfig(s);const r=this.platform.acquireContext(n,a.aspectRatio),l=r&&r.canvas,h=l&&l.height,c=l&&l.width;this.id=i(),this.ctx=r,this.canvas=l,this.width=c,this.height=h,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new sn,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=dt((t=>this.update(t)),a.resizeDelay||0),this._dataChanges=[],Pn[this.id]=this,r&&l?(bt.listen(this,"complete",wn),bt.listen(this,"progress",kn),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:t,maintainAspectRatio:e},width:i,height:n,_aspectRatio:o}=this;return s(t)?e&&o?o:n?i/n:null:t}get data(){return this.config.data}set data(t){this.config.data=t}get options(){return this._options}set options(t){this.config.options=t}get registry(){return en}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():ke(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Te(this.canvas,this.ctx),this}stop(){return bt.stop(this),this}resize(t,e){bt.running(this)?this._resizeBeforeDraw={width:t,height:e}:this._resize(t,e)}_resize(t,e){const i=this.options,s=this.canvas,n=i.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(s,t,e,n),a=i.devicePixelRatio||this.platform.getDevicePixelRatio(),r=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,ke(this,a,!0)&&(this.notifyPlugins("resize",{size:o}),d(i.onResize,[this,o],this),this.attached&&this._doResize(r)&&this.render())}ensureScalesHaveIDs(){u(this.options.scales||{},((t,e)=>{t.id=e}))}buildOrUpdateScales(){const t=this.options,e=t.scales,i=this.scales,s=Object.keys(i).reduce(((t,e)=>(t[e]=!1,t)),{});let n=[];e&&(n=n.concat(Object.keys(e).map((t=>{const i=e[t],s=ln(t,i),n="r"===s,o="x"===s;return{options:i,dposition:n?"chartArea":o?"bottom":"left",dtype:n?"radialLinear":o?"category":"linear"}})))),u(n,(e=>{const n=e.options,o=n.id,a=ln(o,n),r=l(n.type,e.dtype);void 0!==n.position&&vn(n.position,a)===vn(e.dposition)||(n.position=e.dposition),s[o]=!0;let h=null;if(o in i&&i[o].type===r)h=i[o];else{h=new(en.getScale(r))({id:o,type:r,ctx:this.ctx,chart:this}),i[h.id]=h}h.init(n,t)})),u(s,((t,e)=>{t||delete i[e]})),u(i,(t=>{as.configure(this,t,t.options),as.addBox(this,t)}))}_updateMetasets(){const t=this._metasets,e=this.data.datasets.length,i=t.length;if(t.sort(((t,e)=>t.index-e.index)),i>e){for(let t=e;te.length&&delete this._stacks,t.forEach(((t,i)=>{0===e.filter((e=>e===t._dataset)).length&&this._destroyDatasetMeta(i)}))}buildOrUpdateControllers(){const t=[],e=this.data.datasets;let i,s;for(this._removeUnreferencedMetasets(),i=0,s=e.length;i{this.getDatasetMeta(e).controller.reset()}),this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(t){const e=this.config;e.update();const i=this._options=e.createResolver(e.chartOptionScopes(),this.getContext()),s=this._animationsDisabled=!i.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:t,cancelable:!0}))return;const n=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let t=0,e=this.data.datasets.length;t{t.reset()})),this._updateDatasets(t),this.notifyPlugins("afterUpdate",{mode:t}),this._layers.sort(Mn("z","_idx"));const{_active:a,_lastEvent:r}=this;r?this._eventHandler(r,!0):a.length&&this._updateHoverStyles(a,a,!0),this.render()}_updateScales(){u(this.scales,(t=>{as.removeBox(this,t)})),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const t=this.options,e=new Set(Object.keys(this._listeners)),i=new Set(t.events);P(e,i)&&!!this._responsiveListeners===t.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:t}=this,e=this._getUniformDataChanges()||[];for(const{method:i,start:s,count:n}of e){Cn(t,s,"_removeElements"===i?-n:n)}}_getUniformDataChanges(){const t=this._dataChanges;if(!t||!t.length)return;this._dataChanges=[];const e=this.data.datasets.length,i=e=>new Set(t.filter((t=>t[0]===e)).map(((t,e)=>e+","+t.splice(1).join(",")))),s=i(0);for(let t=1;tt.split(","))).map((t=>({method:t[1],start:+t[2],count:+t[3]})))}_updateLayout(t){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;as.update(this,this.width,this.height,t);const e=this.chartArea,i=e.width<=0||e.height<=0;this._layers=[],u(this.boxes,(t=>{i&&"chartArea"===t.position||(t.configure&&t.configure(),this._layers.push(...t._layers()))}),this),this._layers.forEach(((t,e)=>{t._idx=e})),this.notifyPlugins("afterLayout")}_updateDatasets(t){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:t,cancelable:!0})){for(let t=0,e=this.data.datasets.length;t=0;--e)this._drawDataset(t[e]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(t){const e=this.ctx,i=t._clip,s=!i.disabled,n=function(t,e){const{xScale:i,yScale:s}=t;return i&&s?{left:On(i,e,"left"),right:On(i,e,"right"),top:On(s,e,"top"),bottom:On(s,e,"bottom")}:e}(t,this.chartArea),o={meta:t,index:t.index,cancelable:!0};!1!==this.notifyPlugins("beforeDatasetDraw",o)&&(s&&Ie(e,{left:!1===i.left?0:n.left-i.left,right:!1===i.right?this.width:n.right+i.right,top:!1===i.top?0:n.top-i.top,bottom:!1===i.bottom?this.height:n.bottom+i.bottom}),t.controller.draw(),s&&ze(e),o.cancelable=!1,this.notifyPlugins("afterDatasetDraw",o))}isPointInArea(t){return Re(t,this.chartArea,this._minPadding)}getElementsAtEventForMode(t,e,i,s){const n=Xi.modes[e];return"function"==typeof n?n(this,t,i,s):[]}getDatasetMeta(t){const e=this.data.datasets[t],i=this._metasets;let s=i.filter((t=>t&&t._dataset===e)).pop();return s||(s={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e&&e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1},i.push(s)),s}getContext(){return this.$context||(this.$context=Ci(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(t){const e=this.data.datasets[t];if(!e)return!1;const i=this.getDatasetMeta(t);return"boolean"==typeof i.hidden?!i.hidden:!e.hidden}setDatasetVisibility(t,e){this.getDatasetMeta(t).hidden=!e}toggleDataVisibility(t){this._hiddenIndices[t]=!this._hiddenIndices[t]}getDataVisibility(t){return!this._hiddenIndices[t]}_updateVisibility(t,e,i){const s=i?"show":"hide",n=this.getDatasetMeta(t),o=n.controller._resolveAnimations(void 0,s);k(e)?(n.data[e].hidden=!i,this.update()):(this.setDatasetVisibility(t,i),o.update(n,{visible:i}),this.update((e=>e.datasetIndex===t?s:void 0)))}hide(t,e){this._updateVisibility(t,e,!1)}show(t,e){this._updateVisibility(t,e,!0)}_destroyDatasetMeta(t){const e=this._metasets[t];e&&e.controller&&e.controller._destroy(),delete this._metasets[t]}_stop(){let t,e;for(this.stop(),bt.remove(this),t=0,e=this.data.datasets.length;t{e.addEventListener(this,i,s),t[i]=s},s=(t,e,i)=>{t.offsetX=e,t.offsetY=i,this._eventHandler(t)};u(this.options.events,(t=>i(t,s)))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const t=this._responsiveListeners,e=this.platform,i=(i,s)=>{e.addEventListener(this,i,s),t[i]=s},s=(i,s)=>{t[i]&&(e.removeEventListener(this,i,s),delete t[i])},n=(t,e)=>{this.canvas&&this.resize(t,e)};let o;const a=()=>{s("attach",a),this.attached=!0,this.resize(),i("resize",n),i("detach",o)};o=()=>{this.attached=!1,s("resize",n),this._stop(),this._resize(0,0),i("attach",a)},e.isAttached(this.canvas)?a():o()}unbindEvents(){u(this._listeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._listeners={},u(this._responsiveListeners,((t,e)=>{this.platform.removeEventListener(this,e,t)})),this._responsiveListeners=void 0}updateHoverStyle(t,e,i){const s=i?"set":"remove";let n,o,a,r;for("dataset"===e&&(n=this.getDatasetMeta(t[0].datasetIndex),n.controller["_"+s+"DatasetHoverStyle"]()),a=0,r=t.length;a{const i=this.getDatasetMeta(t);if(!i)throw new Error("No dataset found at index "+t);return{datasetIndex:t,element:i.data[e],index:e}}));!f(i,e)&&(this._active=i,this._lastEvent=null,this._updateHoverStyles(i,e))}notifyPlugins(t,e,i){return this._plugins.notify(this,t,e,i)}isPluginEnabled(t){return 1===this._plugins._cache.filter((e=>e.plugin.id===t)).length}_updateHoverStyles(t,e,i){const s=this.options.hover,n=(t,e)=>t.filter((t=>!e.some((e=>t.datasetIndex===e.datasetIndex&&t.index===e.index)))),o=n(e,t),a=i?t:n(t,e);o.length&&this.updateHoverStyle(o,s.mode,!1),a.length&&s.mode&&this.updateHoverStyle(a,s.mode,!0)}_eventHandler(t,e){const i={event:t,replay:e,cancelable:!0,inChartArea:this.isPointInArea(t)},s=e=>(e.options.events||this.options.events).includes(t.native.type);if(!1===this.notifyPlugins("beforeEvent",i,s))return;const n=this._handleEvent(t,e,i.inChartArea);return i.cancelable=!1,this.notifyPlugins("afterEvent",i,s),(n||i.changed)&&this.render(),this}_handleEvent(t,e,i){const{_active:s=[],options:n}=this,o=e,a=this._getActiveElements(t,s,i,o),r=D(t),l=function(t,e,i,s){return i&&"mouseout"!==t.type?s?e:t:null}(t,this._lastEvent,i,r);i&&(this._lastEvent=null,d(n.onHover,[t,a,this],this),r&&d(n.onClick,[t,a,this],this));const h=!f(a,s);return(h||e)&&(this._active=a,this._updateHoverStyles(a,s,e)),this._lastEvent=l,h}_getActiveElements(t,e,i,s){if("mouseout"===t.type)return[];if(!i)return e;const n=this.options.hover;return this.getElementsAtEventForMode(t,n.mode,n,s)}}function Tn(){return u(An.instances,(t=>t._plugins.invalidate()))}function Ln(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class En{static override(t){Object.assign(En.prototype,t)}options;constructor(t){this.options=t||{}}init(){}formats(){return Ln()}parse(){return Ln()}format(){return Ln()}add(){return Ln()}diff(){return Ln()}startOf(){return Ln()}endOf(){return Ln()}}var Rn={_date:En};function In(t){const e=t.iScale,i=function(t,e){if(!t._cache.$bar){const i=t.getMatchingVisibleMetas(e);let s=[];for(let e=0,n=i.length;et-e)))}return t._cache.$bar}(e,t.type);let s,n,o,a,r=e._length;const l=()=>{32767!==o&&-32768!==o&&(k(a)&&(r=Math.min(r,Math.abs(o-a)||r)),a=o)};for(s=0,n=i.length;sMath.abs(r)&&(l=r,h=a),e[i.axis]=h,e._custom={barStart:l,barEnd:h,start:n,end:o,min:a,max:r}}(t,e,i,s):e[i.axis]=i.parse(t,s),e}function Fn(t,e,i,s){const n=t.iScale,o=t.vScale,a=n.getLabels(),r=n===o,l=[];let h,c,d,u;for(h=i,c=i+s;ht.x,i="left",s="right"):(e=t.base"spacing"!==t,_indexable:t=>"spacing"!==t&&!t.startsWith("borderDash")&&!t.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(t){const e=t.data;if(e.labels.length&&e.datasets.length){const{labels:{pointStyle:i,color:s}}=t.legend.options;return e.labels.map(((e,n)=>{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}}};constructor(t,e){super(t,e),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(t,e){const i=this.getDataset().data,s=this._cachedMeta;if(!1===this._parsing)s._parsed=i;else{let n,a,r=t=>+i[t];if(o(i[t])){const{key:t="value"}=this._parsing;r=e=>+M(i[e],t)}for(n=t,a=t+e;nZ(t,r,l,!0)?1:Math.max(e,e*i,s,s*i),g=(t,e,s)=>Z(t,r,l,!0)?-1:Math.min(e,e*i,s,s*i),p=f(0,h,d),m=f(E,c,u),x=g(C,h,d),b=g(C+E,c,u);s=(p-x)/2,n=(m-b)/2,o=-(p+x)/2,a=-(m+b)/2}return{ratioX:s,ratioY:n,offsetX:o,offsetY:a}}(u,d,r),x=(i.width-o)/f,b=(i.height-o)/g,_=Math.max(Math.min(x,b)/2,0),y=c(this.options.radius,_),v=(y-Math.max(y*r,0))/this._getVisibleDatasetWeightTotal();this.offsetX=p*y,this.offsetY=m*y,s.total=this.calculateTotal(),this.outerRadius=y-v*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-v*l,0),this.updateElements(n,0,n.length,t)}_circumference(t,e){const i=this.options,s=this._cachedMeta,n=this._getCircumference();return e&&i.animation.animateRotate||!this.chart.getDataVisibility(t)||null===s._parsed[t]||s.data[t].hidden?0:this.calculateCircumference(s._parsed[t]*n/O)}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.chartArea,r=o.options.animation,l=(a.left+a.right)/2,h=(a.top+a.bottom)/2,c=n&&r.animateScale,d=c?0:this.innerRadius,u=c?0:this.outerRadius,{sharedOptions:f,includeOptions:g}=this._getSharedOptions(e,s);let p,m=this._getRotation();for(p=0;p0&&!isNaN(t)?O*(Math.abs(t)/e):0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t],i.options.locale);return{label:s[t]||"",value:n}}getMaxBorderWidth(t){let e=0;const i=this.chart;let s,n,o,a,r;if(!t)for(s=0,n=i.data.datasets.length;s{const o=t.getDatasetMeta(0).controller.getStyle(n);return{text:e,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:s,lineWidth:o.borderWidth,pointStyle:i,hidden:!t.getDataVisibility(n),index:n}}))}return[]}},onClick(t,e,i){i.chart.toggleDataVisibility(e.index),i.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(t,e){super(t,e),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart,s=i.data.labels||[],n=ne(e._parsed[t].r,i.options.locale);return{label:s[t]||"",value:n}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)}getMinMax(){const t=this._cachedMeta,e={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return t.data.forEach(((t,i)=>{const s=this.getParsed(i).r;!isNaN(s)&&this.chart.getDataVisibility(i)&&(se.max&&(e.max=s))})),e}_updateRadius(){const t=this.chart,e=t.chartArea,i=t.options,s=Math.min(e.right-e.left,e.bottom-e.top),n=Math.max(s/2,0),o=(n-Math.max(i.cutoutPercentage?n/100*i.cutoutPercentage:1,0))/t.getVisibleDatasetCount();this.outerRadius=n-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(t,e,i,s){const n="reset"===s,o=this.chart,a=o.options.animation,r=this._cachedMeta.rScale,l=r.xCenter,h=r.yCenter,c=r.getIndexAngle(0)-.5*C;let d,u=c;const f=360/this.countVisibleElements();for(d=0;d{!isNaN(this.getParsed(i).r)&&this.chart.getDataVisibility(i)&&e++})),e}_computeAngle(t,e,i){return this.chart.getDataVisibility(t)?$(this.resolveDataElementOptions(t,e).angle||i):0}}var Yn=Object.freeze({__proto__:null,BarController:class extends Ns{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(t,e,i,s){return Fn(t,e,i,s)}parseArrayData(t,e,i,s){return Fn(t,e,i,s)}parseObjectData(t,e,i,s){const{iScale:n,vScale:o}=t,{xAxisKey:a="x",yAxisKey:r="y"}=this._parsing,l="x"===n.axis?a:r,h="x"===o.axis?a:r,c=[];let d,u,f,g;for(d=i,u=i+s;dt.controller.options.grouped)),o=i.options.stacked,a=[],r=this._cachedMeta.controller.getParsed(e),l=r&&r[i.axis],h=t=>{const e=t._parsed.find((t=>t[i.axis]===l)),n=e&&e[t.vScale.axis];if(s(n)||isNaN(n))return!0};for(const i of n)if((void 0===e||!h(i))&&((!1===o||-1===a.indexOf(i.stack)||void 0===o&&void 0===i.stack)&&a.push(i.stack),i.index===t))break;return a.length||a.push(void 0),a}_getStackCount(t){return this._getStacks(void 0,t).length}_getStackIndex(t,e,i){const s=this._getStacks(t,i),n=void 0!==e?s.indexOf(e):-1;return-1===n?s.length-1:n}_getRuler(){const t=this.options,e=this._cachedMeta,i=e.iScale,s=[];let n,o;for(n=0,o=e.data.length;n=i?1:-1)}(u,e,r)*a,f===r&&(x-=u/2);const t=e.getPixelForDecimal(0),s=e.getPixelForDecimal(1),o=Math.min(t,s),h=Math.max(t,s);x=Math.max(Math.min(x,h),o),d=x+u,i&&!c&&(l._stacks[e.axis]._visualValues[n]=e.getValueForPixel(d)-e.getValueForPixel(x))}if(x===e.getPixelForValue(r)){const t=F(u)*e.getLineWidthForValue(r)/2;x+=t,u-=t}return{size:u,base:x,head:d,center:d+u/2}}_calculateBarIndexPixels(t,e){const i=e.scale,n=this.options,o=n.skipNull,a=l(n.maxBarThickness,1/0);let r,h;if(e.grouped){const i=o?this._getStackCount(t):e.stackCount,l="flex"===n.barThickness?function(t,e,i,s){const n=e.pixels,o=n[t];let a=t>0?n[t-1]:null,r=t=0;--i)e=Math.max(e,t[i].size(this.resolveDataElementOptions(i))/2);return e>0&&e}getLabelAndValue(t){const e=this._cachedMeta,i=this.chart.data.labels||[],{xScale:s,yScale:n}=e,o=this.getParsed(t),a=s.getLabelForValue(o.x),r=n.getLabelForValue(o.y),l=o._custom;return{label:i[t]||"",value:"("+a+", "+r+(l?", "+l:"")+")"}}update(t){const e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)}updateElements(t,e,i,s){const n="reset"===s,{iScale:o,vScale:a}=this._cachedMeta,{sharedOptions:r,includeOptions:l}=this._getSharedOptions(e,s),h=o.axis,c=a.axis;for(let d=e;d0&&this.getParsed(e-1);for(let i=0;i<_;++i){const g=t[i],_=x?g:{};if(i=b){_.skip=!0;continue}const v=this.getParsed(i),M=s(v[f]),w=_[u]=a.getPixelForValue(v[u],i),k=_[f]=o||M?r.getBasePixel():r.getPixelForValue(l?this.applyStack(r,v,l):v[f],i);_.skip=isNaN(w)||isNaN(k)||M,_.stop=i>0&&Math.abs(v[u]-y[u])>m,p&&(_.parsed=v,_.raw=h.data[i]),d&&(_.options=c||this.resolveDataElementOptions(i,g.active?"active":n)),x||this.updateElement(g,i,_,n),y=v}}getMaxOverflow(){const t=this._cachedMeta,e=t.dataset,i=e.options&&e.options.borderWidth||0,s=t.data||[];if(!s.length)return i;const n=s[0].size(this.resolveDataElementOptions(0)),o=s[s.length-1].size(this.resolveDataElementOptions(s.length-1));return Math.max(i,n,o)/2}draw(){const t=this._cachedMeta;t.dataset.updateControlPoints(this.chart.chartArea,t.iScale.axis),super.draw()}},PieController:class extends jn{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:$n,RadarController:class extends Ns{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(t){const e=this._cachedMeta.vScale,i=this.getParsed(t);return{label:e.getLabels()[t],value:""+e.getLabelForValue(i[e.axis])}}parseObjectData(t,e,i,s){return ii.bind(this)(t,e,i,s)}update(t){const e=this._cachedMeta,i=e.dataset,s=e.data||[],n=e.iScale.getLabels();if(i.points=s,"resize"!==t){const e=this.resolveDatasetElementOptions(t);this.options.showLine||(e.borderWidth=0);const o={_loop:!0,_fullLoop:n.length===s.length,options:e};this.updateElement(i,void 0,o,t)}this.updateElements(s,0,s.length,t)}updateElements(t,e,i,s){const n=this._cachedMeta.rScale,o="reset"===s;for(let a=e;a0&&this.getParsed(e-1);for(let c=e;c0&&Math.abs(i[f]-_[f])>x,m&&(p.parsed=i,p.raw=h.data[c]),u&&(p.options=d||this.resolveDataElementOptions(c,e.active?"active":n)),b||this.updateElement(e,c,p,n),_=i}this.updateSharedOptions(d,n,c)}getMaxOverflow(){const t=this._cachedMeta,e=t.data||[];if(!this.options.showLine){let t=0;for(let i=e.length-1;i>=0;--i)t=Math.max(t,e[i].size(this.resolveDataElementOptions(i))/2);return t>0&&t}const i=t.dataset,s=i.options&&i.options.borderWidth||0;if(!e.length)return s;const n=e[0].size(this.resolveDataElementOptions(0)),o=e[e.length-1].size(this.resolveDataElementOptions(e.length-1));return Math.max(s,n,o)/2}}});function Un(t,e,i,s){const n=vi(t.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]);const o=(i-e)/2,a=Math.min(o,s*e/2),r=t=>{const e=(i-Math.min(o,t))*s/2;return J(t,0,Math.min(o,e))};return{outerStart:r(n.outerStart),outerEnd:r(n.outerEnd),innerStart:J(n.innerStart,0,a),innerEnd:J(n.innerEnd,0,a)}}function Xn(t,e,i,s){return{x:i+t*Math.cos(e),y:s+t*Math.sin(e)}}function qn(t,e,i,s,n,o){const{x:a,y:r,startAngle:l,pixelMargin:h,innerRadius:c}=e,d=Math.max(e.outerRadius+s+i-h,0),u=c>0?c+s+i+h:0;let f=0;const g=n-l;if(s){const t=((c>0?c-s:0)+(d>0?d-s:0))/2;f=(g-(0!==t?g*t/(t+s):g))/2}const p=(g-Math.max(.001,g*d-i/C)/d)/2,m=l+p+f,x=n-p-f,{outerStart:b,outerEnd:_,innerStart:y,innerEnd:v}=Un(e,u,d,x-m),M=d-b,w=d-_,k=m+b/M,S=x-_/w,P=u+y,D=u+v,O=m+y/P,A=x-v/D;if(t.beginPath(),o){const e=(k+S)/2;if(t.arc(a,r,d,k,e),t.arc(a,r,d,e,S),_>0){const e=Xn(w,S,a,r);t.arc(e.x,e.y,_,S,x+E)}const i=Xn(D,x,a,r);if(t.lineTo(i.x,i.y),v>0){const e=Xn(D,A,a,r);t.arc(e.x,e.y,v,x+E,A+Math.PI)}const s=(x-v/u+(m+y/u))/2;if(t.arc(a,r,u,x-v/u,s,!0),t.arc(a,r,u,s,m+y/u,!0),y>0){const e=Xn(P,O,a,r);t.arc(e.x,e.y,y,O+Math.PI,m-E)}const n=Xn(M,m,a,r);if(t.lineTo(n.x,n.y),b>0){const e=Xn(M,k,a,r);t.arc(e.x,e.y,b,m-E,k)}}else{t.moveTo(a,r);const e=Math.cos(k)*d+a,i=Math.sin(k)*d+r;t.lineTo(e,i);const s=Math.cos(S)*d+a,n=Math.sin(S)*d+r;t.lineTo(s,n)}t.closePath()}function Kn(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r,options:l}=e,{borderWidth:h,borderJoinStyle:c,borderDash:d,borderDashOffset:u}=l,f="inner"===l.borderAlign;if(!h)return;t.setLineDash(d||[]),t.lineDashOffset=u,f?(t.lineWidth=2*h,t.lineJoin=c||"round"):(t.lineWidth=h,t.lineJoin=c||"bevel");let g=e.endAngle;if(o){qn(t,e,i,s,g,n);for(let e=0;en?(h=n/l,t.arc(o,a,l,i+h,s-h,!0)):t.arc(o,a,n,i+E,s-E),t.closePath(),t.clip()}(t,e,g),o||(qn(t,e,i,s,g,n),t.stroke())}function Gn(t,e,i=e){t.lineCap=l(i.borderCapStyle,e.borderCapStyle),t.setLineDash(l(i.borderDash,e.borderDash)),t.lineDashOffset=l(i.borderDashOffset,e.borderDashOffset),t.lineJoin=l(i.borderJoinStyle,e.borderJoinStyle),t.lineWidth=l(i.borderWidth,e.borderWidth),t.strokeStyle=l(i.borderColor,e.borderColor)}function Zn(t,e,i){t.lineTo(i.x,i.y)}function Jn(t,e,i={}){const s=t.length,{start:n=0,end:o=s-1}=i,{start:a,end:r}=e,l=Math.max(n,a),h=Math.min(o,r),c=nr&&o>r;return{count:s,start:l,loop:e.loop,ilen:h(a+(h?r-t:t))%o,_=()=>{f!==g&&(t.lineTo(m,g),t.lineTo(m,f),t.lineTo(m,p))};for(l&&(d=n[b(0)],t.moveTo(d.x,d.y)),c=0;c<=r;++c){if(d=n[b(c)],d.skip)continue;const e=d.x,i=d.y,s=0|e;s===u?(ig&&(g=i),m=(x*m+e)/++x):(_(),t.lineTo(e,i),u=s,x=0,f=g=i),p=i}_()}function eo(t){const e=t.options,i=e.borderDash&&e.borderDash.length;return!(t._decimated||t._loop||e.tension||"monotone"===e.cubicInterpolationMode||e.stepped||i)?to:Qn}const io="function"==typeof Path2D;function so(t,e,i,s){io&&!e.options.segment?function(t,e,i,s){let n=e._path;n||(n=e._path=new Path2D,e.path(n,i,s)&&n.closePath()),Gn(t,e.options),t.stroke(n)}(t,e,i,s):function(t,e,i,s){const{segments:n,options:o}=e,a=eo(e);for(const r of n)Gn(t,o,r.style),t.beginPath(),a(t,e,r,{start:i,end:i+s-1})&&t.closePath(),t.stroke()}(t,e,i,s)}class no extends Hs{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:t=>"borderDash"!==t&&"fill"!==t};constructor(t){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,t&&Object.assign(this,t)}updateControlPoints(t,e){const i=this.options;if((i.tension||"monotone"===i.cubicInterpolationMode)&&!i.stepped&&!this._pointsUpdated){const s=i.spanGaps?this._loop:this._fullLoop;hi(this._points,i,t,s,e),this._pointsUpdated=!0}}set points(t){this._points=t,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=zi(this,this.options.segment))}first(){const t=this.segments,e=this.points;return t.length&&e[t[0].start]}last(){const t=this.segments,e=this.points,i=t.length;return i&&e[t[i-1].end]}interpolate(t,e){const i=this.options,s=t[e],n=this.points,o=Ii(this,{property:e,start:s,end:s});if(!o.length)return;const a=[],r=function(t){return t.stepped?pi:t.tension||"monotone"===t.cubicInterpolationMode?mi:gi}(i);let l,h;for(l=0,h=o.length;l"borderDash"!==t};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(t){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,t&&Object.assign(this,t)}inRange(t,e,i){const s=this.getProps(["x","y"],i),{angle:n,distance:o}=X(s,{x:t,y:e}),{startAngle:a,endAngle:r,innerRadius:h,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],i),u=(this.options.spacing+this.options.borderWidth)/2,f=l(d,r-a),g=Z(n,a,r)&&a!==r,p=f>=O||g,m=tt(o,h+u,c+u);return p&&m}getCenterPoint(t){const{x:e,y:i,startAngle:s,endAngle:n,innerRadius:o,outerRadius:a}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),{offset:r,spacing:l}=this.options,h=(s+n)/2,c=(o+a+l+r)/2;return{x:e+Math.cos(h)*c,y:i+Math.sin(h)*c}}tooltipPosition(t){return this.getCenterPoint(t)}draw(t){const{options:e,circumference:i}=this,s=(e.offset||0)/4,n=(e.spacing||0)/2,o=e.circular;if(this.pixelMargin="inner"===e.borderAlign?.33:0,this.fullCircles=i>O?Math.floor(i/O):0,0===i||this.innerRadius<0||this.outerRadius<0)return;t.save();const a=(this.startAngle+this.endAngle)/2;t.translate(Math.cos(a)*s,Math.sin(a)*s);const r=s*(1-Math.sin(Math.min(C,i||0)));t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,function(t,e,i,s,n){const{fullCircles:o,startAngle:a,circumference:r}=e;let l=e.endAngle;if(o){qn(t,e,i,s,l,n);for(let e=0;e("string"==typeof e?(i=t.push(e)-1,s.unshift({index:i,label:e})):isNaN(e)&&(i=null),i))(t,e,i,s);return n!==t.lastIndexOf(e)?i:n}function po(t){const e=this.getLabels();return t>=0&&ts=e?s:t,a=t=>n=i?n:t;if(t){const t=F(s),e=F(n);t<0&&e<0?a(0):t>0&&e>0&&o(0)}if(s===n){let e=0===n?1:Math.abs(.05*n);a(n+e),t||o(s-e)}this.min=s,this.max=n}getTickLimit(){const t=this.options.ticks;let e,{maxTicksLimit:i,stepSize:s}=t;return s?(e=Math.ceil(this.max/s)-Math.floor(this.min/s)+1,e>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${s} would result generating up to ${e} ticks. Limiting to 1000.`),e=1e3)):(e=this.computeTickLimit(),i=i||11),i&&(e=Math.min(i,e)),e}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const t=this.options,e=t.ticks;let i=this.getTickLimit();i=Math.max(2,i);const n=function(t,e){const i=[],{bounds:n,step:o,min:a,max:r,precision:l,count:h,maxTicks:c,maxDigits:d,includeBounds:u}=t,f=o||1,g=c-1,{min:p,max:m}=e,x=!s(a),b=!s(r),_=!s(h),y=(m-p)/(d+1);let v,M,w,k,S=B((m-p)/g/f)*f;if(S<1e-14&&!x&&!b)return[{value:p},{value:m}];k=Math.ceil(m/S)-Math.floor(p/S),k>g&&(S=B(k*S/g/f)*f),s(l)||(v=Math.pow(10,l),S=Math.ceil(S*v)/v),"ticks"===n?(M=Math.floor(p/S)*S,w=Math.ceil(m/S)*S):(M=p,w=m),x&&b&&o&&H((r-a)/o,S/1e3)?(k=Math.round(Math.min((r-a)/S,c)),S=(r-a)/k,M=a,w=r):_?(M=x?a:M,w=b?r:w,k=h-1,S=(w-M)/k):(k=(w-M)/S,k=V(k,Math.round(k),S/1e3)?Math.round(k):Math.ceil(k));const P=Math.max(U(S),U(M));v=Math.pow(10,s(l)?P:l),M=Math.round(M*v)/v,w=Math.round(w*v)/v;let D=0;for(x&&(u&&M!==a?(i.push({value:a}),Mr)break;i.push({value:t})}return b&&u&&w!==r?i.length&&V(i[i.length-1].value,r,mo(r,y,t))?i[i.length-1].value=r:i.push({value:r}):b&&w!==r||i.push({value:w}),i}({maxTicks:i,bounds:t.bounds,min:t.min,max:t.max,precision:e.precision,step:e.stepSize,count:e.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:e.minRotation||0,includeBounds:!1!==e.includeBounds},this._range||this);return"ticks"===t.bounds&&j(n,this,"value"),t.reverse?(n.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),n}configure(){const t=this.ticks;let e=this.min,i=this.max;if(super.configure(),this.options.offset&&t.length){const s=(i-e)/Math.max(t.length-1,1)/2;e-=s,i+=s}this._startValue=e,this._endValue=i,this._valueRange=i-e}getLabelForValue(t){return ne(t,this.chart.options.locale,this.options.ticks.format)}}class bo extends xo{static id="linear";static defaults={ticks:{callback:ae.formatters.numeric}};determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?t:0,this.max=a(e)?e:1,this.handleTickRangeOptions()}computeTickLimit(){const t=this.isHorizontal(),e=t?this.width:this.height,i=$(this.options.ticks.minRotation),s=(t?Math.sin(i):Math.cos(i))||.001,n=this._resolveTickFontOptions(0);return Math.ceil(e/Math.min(40,n.lineHeight/s))}getPixelForValue(t){return null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getValueForPixel(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange}}const _o=t=>Math.floor(z(t)),yo=(t,e)=>Math.pow(10,_o(t)+e);function vo(t){return 1===t/Math.pow(10,_o(t))}function Mo(t,e,i){const s=Math.pow(10,i),n=Math.floor(t/s);return Math.ceil(e/s)-n}function wo(t,{min:e,max:i}){e=r(t.min,e);const s=[],n=_o(e);let o=function(t,e){let i=_o(e-t);for(;Mo(t,e,i)>10;)i++;for(;Mo(t,e,i)<10;)i--;return Math.min(i,_o(t))}(e,i),a=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),h=n>o?Math.pow(10,n):0,c=Math.round((e-h)*a)/a,d=Math.floor((e-h)/l/10)*l*10;let u=Math.floor((c-d)/Math.pow(10,o)),f=r(t.min,Math.round((h+d+u*Math.pow(10,o))*a)/a);for(;f=10?u=u<15?15:20:u++,u>=20&&(o++,u=2,a=o>=0?1:a),f=Math.round((h+d+u*Math.pow(10,o))*a)/a;const g=r(t.max,f);return s.push({value:g,major:vo(g),significand:u}),s}class ko extends Js{static id="logarithmic";static defaults={ticks:{callback:ae.formatters.logarithmic,major:{enabled:!0}}};constructor(t){super(t),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(t,e){const i=xo.prototype.parse.apply(this,[t,e]);if(0!==i)return a(i)&&i>0?i:null;this._zero=!0}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!0);this.min=a(t)?Math.max(0,t):null,this.max=a(e)?Math.max(0,e):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!a(this._userMin)&&(this.min=t===yo(this.min,0)?yo(this.min,-1):yo(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let i=this.min,s=this.max;const n=e=>i=t?i:e,o=t=>s=e?s:t;i===s&&(i<=0?(n(1),o(10)):(n(yo(i,-1)),o(yo(s,1)))),i<=0&&n(yo(s,-1)),s<=0&&o(yo(i,1)),this.min=i,this.max=s}buildTicks(){const t=this.options,e=wo({min:this._userMin,max:this._userMax},this);return"ticks"===t.bounds&&j(e,this,"value"),t.reverse?(e.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),e}getLabelForValue(t){return void 0===t?"0":ne(t,this.chart.options.locale,this.options.ticks.format)}configure(){const t=this.min;super.configure(),this._startValue=z(t),this._valueRange=z(this.max)-z(t)}getPixelForValue(t){return void 0!==t&&0!==t||(t=this.min),null===t||isNaN(t)?NaN:this.getPixelForDecimal(t===this.min?0:(z(t)-this._startValue)/this._valueRange)}getValueForPixel(t){const e=this.getDecimalForPixel(t);return Math.pow(10,this._startValue+e*this._valueRange)}}function So(t){const e=t.ticks;if(e.display&&t.display){const t=ki(e.backdropPadding);return l(e.font&&e.font.size,ue.font.size)+t.height}return 0}function Po(t,e,i,s,n){return t===s||t===n?{start:e-i/2,end:e+i/2}:tn?{start:e-i,end:e}:{start:e,end:e+i}}function Do(t){const e={l:t.left+t._padding.left,r:t.right-t._padding.right,t:t.top+t._padding.top,b:t.bottom-t._padding.bottom},i=Object.assign({},e),s=[],o=[],a=t._pointLabels.length,r=t.options.pointLabels,l=r.centerPointLabels?C/a:0;for(let u=0;ue.r&&(r=(s.end-e.r)/o,t.r=Math.max(t.r,e.r+r)),n.starte.b&&(l=(n.end-e.b)/a,t.b=Math.max(t.b,e.b+l))}function Oo(t,e,i){const s=t.drawingArea,{extra:n,additionalAngle:o,padding:a,size:r}=i,l=t.getPointPosition(e,s+n+a,o),h=Math.round(Y(G(l.angle+E))),c=function(t,e,i){90===i||270===i?t-=e/2:(i>270||i<90)&&(t-=e);return t}(l.y,r.h,h),d=function(t){if(0===t||180===t)return"center";if(t<180)return"left";return"right"}(h),u=function(t,e,i){"right"===i?t-=e:"center"===i&&(t-=e/2);return t}(l.x,r.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:u,top:c,right:u+r.w,bottom:c+r.h}}function Ao(t,e){if(!e)return!0;const{left:i,top:s,right:n,bottom:o}=t;return!(Re({x:i,y:s},e)||Re({x:i,y:o},e)||Re({x:n,y:s},e)||Re({x:n,y:o},e))}function To(t,e,i){const{left:n,top:o,right:a,bottom:r}=i,{backdropColor:l}=e;if(!s(l)){const i=wi(e.borderRadius),s=ki(e.backdropPadding);t.fillStyle=l;const h=n-s.left,c=o-s.top,d=a-n+s.width,u=r-o+s.height;Object.values(i).some((t=>0!==t))?(t.beginPath(),He(t,{x:h,y:c,w:d,h:u,radius:i}),t.fill()):t.fillRect(h,c,d,u)}}function Lo(t,e,i,s){const{ctx:n}=t;if(i)n.arc(t.xCenter,t.yCenter,e,0,O);else{let i=t.getPointPosition(0,e);n.moveTo(i.x,i.y);for(let o=1;ot,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(t){super(t),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const t=this._padding=ki(So(this.options)/2),e=this.width=this.maxWidth-t.width,i=this.height=this.maxHeight-t.height;this.xCenter=Math.floor(this.left+e/2+t.left),this.yCenter=Math.floor(this.top+i/2+t.top),this.drawingArea=Math.floor(Math.min(e,i)/2)}determineDataLimits(){const{min:t,max:e}=this.getMinMax(!1);this.min=a(t)&&!isNaN(t)?t:0,this.max=a(e)&&!isNaN(e)?e:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/So(this.options))}generateTickLabels(t){xo.prototype.generateTickLabels.call(this,t),this._pointLabels=this.getLabels().map(((t,e)=>{const i=d(this.options.pointLabels.callback,[t,e],this);return i||0===i?i:""})).filter(((t,e)=>this.chart.getDataVisibility(e)))}fit(){const t=this.options;t.display&&t.pointLabels.display?Do(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(t,e,i,s){this.xCenter+=Math.floor((t-e)/2),this.yCenter+=Math.floor((i-s)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(t,e,i,s))}getIndexAngle(t){return G(t*(O/(this._pointLabels.length||1))+$(this.options.startAngle||0))}getDistanceFromCenterForValue(t){if(s(t))return NaN;const e=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-t)*e:(t-this.min)*e}getValueForDistanceFromCenter(t){if(s(t))return NaN;const e=t/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-e:this.min+e}getPointLabelContext(t){const e=this._pointLabels||[];if(t>=0&&t=0;n--){const e=t._pointLabelItems[n];if(!e.visible)continue;const o=s.setContext(t.getPointLabelContext(n));To(i,o,e);const a=Si(o.font),{x:r,y:l,textAlign:h}=e;Ne(i,t._pointLabels[n],r,l+a.lineHeight/2,a,{color:o.color,textAlign:h,textBaseline:"middle"})}}(this,o),s.display&&this.ticks.forEach(((t,e)=>{if(0!==e||0===e&&this.min<0){r=this.getDistanceFromCenterForValue(t.value);const i=this.getContext(e),a=s.setContext(i),l=n.setContext(i);!function(t,e,i,s,n){const o=t.ctx,a=e.circular,{color:r,lineWidth:l}=e;!a&&!s||!r||!l||i<0||(o.save(),o.strokeStyle=r,o.lineWidth=l,o.setLineDash(n.dash||[]),o.lineDashOffset=n.dashOffset,o.beginPath(),Lo(t,i,a,s),o.closePath(),o.stroke(),o.restore())}(this,a,r,o,l)}})),i.display){for(t.save(),a=o-1;a>=0;a--){const s=i.setContext(this.getPointLabelContext(a)),{color:n,lineWidth:o}=s;o&&n&&(t.lineWidth=o,t.strokeStyle=n,t.setLineDash(s.borderDash),t.lineDashOffset=s.borderDashOffset,r=this.getDistanceFromCenterForValue(e.reverse?this.min:this.max),l=this.getPointPosition(a,r),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(l.x,l.y),t.stroke())}t.restore()}}drawBorder(){}drawLabels(){const t=this.ctx,e=this.options,i=e.ticks;if(!i.display)return;const s=this.getIndexAngle(0);let n,o;t.save(),t.translate(this.xCenter,this.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",this.ticks.forEach(((s,a)=>{if(0===a&&this.min>=0&&!e.reverse)return;const r=i.setContext(this.getContext(a)),l=Si(r.font);if(n=this.getDistanceFromCenterForValue(this.ticks[a].value),r.showLabelBackdrop){t.font=l.string,o=t.measureText(s.label).width,t.fillStyle=r.backdropColor;const e=ki(r.backdropPadding);t.fillRect(-o/2-e.left,-n-l.size/2-e.top,o+e.width,l.size+e.height)}Ne(t,s.label,0,-n,l,{color:r.color,strokeColor:r.textStrokeColor,strokeWidth:r.textStrokeWidth})})),t.restore()}drawTitle(){}}const Ro={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},Io=Object.keys(Ro);function zo(t,e){return t-e}function Fo(t,e){if(s(e))return null;const i=t._adapter,{parser:n,round:o,isoWeekday:r}=t._parseOpts;let l=e;return"function"==typeof n&&(l=n(l)),a(l)||(l="string"==typeof n?i.parse(l,n):i.parse(l)),null===l?null:(o&&(l="week"!==o||!N(r)&&!0!==r?i.startOf(l,o):i.startOf(l,"isoWeek",r)),+l)}function Vo(t,e,i,s){const n=Io.length;for(let o=Io.indexOf(t);o=e?i[s]:i[n]]=!0}}else t[e]=!0}function Wo(t,e,i){const s=[],n={},o=e.length;let a,r;for(a=0;a=0&&(e[l].major=!0);return e}(t,s,n,i):s}class No extends Js{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(t){super(t),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(t,e={}){const i=t.time||(t.time={}),s=this._adapter=new Rn._date(t.adapters.date);s.init(e),b(i.displayFormats,s.formats()),this._parseOpts={parser:i.parser,round:i.round,isoWeekday:i.isoWeekday},super.init(t),this._normalized=e.normalized}parse(t,e){return void 0===t?null:Fo(this,t)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const t=this.options,e=this._adapter,i=t.time.unit||"day";let{min:s,max:n,minDefined:o,maxDefined:r}=this.getUserBounds();function l(t){o||isNaN(t.min)||(s=Math.min(s,t.min)),r||isNaN(t.max)||(n=Math.max(n,t.max))}o&&r||(l(this._getLabelBounds()),"ticks"===t.bounds&&"labels"===t.ticks.source||l(this.getMinMax(!1))),s=a(s)&&!isNaN(s)?s:+e.startOf(Date.now(),i),n=a(n)&&!isNaN(n)?n:+e.endOf(Date.now(),i)+1,this.min=Math.min(s,n-1),this.max=Math.max(s+1,n)}_getLabelBounds(){const t=this.getLabelTimestamps();let e=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],i=t[t.length-1]),{min:e,max:i}}buildTicks(){const t=this.options,e=t.time,i=t.ticks,s="labels"===i.source?this.getLabelTimestamps():this._generate();"ticks"===t.bounds&&s.length&&(this.min=this._userMin||s[0],this.max=this._userMax||s[s.length-1]);const n=this.min,o=nt(s,n,this.max);return this._unit=e.unit||(i.autoSkip?Vo(e.minUnit,this.min,this.max,this._getLabelCapacity(n)):function(t,e,i,s,n){for(let o=Io.length-1;o>=Io.indexOf(i);o--){const i=Io[o];if(Ro[i].common&&t._adapter.diff(n,s,i)>=e-1)return i}return Io[i?Io.indexOf(i):0]}(this,o.length,e.minUnit,this.min,this.max)),this._majorUnit=i.major.enabled&&"year"!==this._unit?function(t){for(let e=Io.indexOf(t)+1,i=Io.length;e+t.value)))}initOffsets(t=[]){let e,i,s=0,n=0;this.options.offset&&t.length&&(e=this.getDecimalForValue(t[0]),s=1===t.length?1-e:(this.getDecimalForValue(t[1])-e)/2,i=this.getDecimalForValue(t[t.length-1]),n=1===t.length?i:(i-this.getDecimalForValue(t[t.length-2]))/2);const o=t.length<3?.5:.25;s=J(s,0,o),n=J(n,0,o),this._offsets={start:s,end:n,factor:1/(s+1+n)}}_generate(){const t=this._adapter,e=this.min,i=this.max,s=this.options,n=s.time,o=n.unit||Vo(n.minUnit,e,i,this._getLabelCapacity(e)),a=l(s.ticks.stepSize,1),r="week"===o&&n.isoWeekday,h=N(r)||!0===r,c={};let d,u,f=e;if(h&&(f=+t.startOf(f,"isoWeek",r)),f=+t.startOf(f,h?"day":o),t.diff(i,e,o)>1e5*a)throw new Error(e+" and "+i+" are too far apart with stepSize of "+a+" "+o);const g="data"===s.ticks.source&&this.getDataTimestamps();for(d=f,u=0;d+t))}getLabelForValue(t){const e=this._adapter,i=this.options.time;return i.tooltipFormat?e.format(t,i.tooltipFormat):e.format(t,i.displayFormats.datetime)}format(t,e){const i=this.options.time.displayFormats,s=this._unit,n=e||i[s];return this._adapter.format(t,n)}_tickFormatFunction(t,e,i,s){const n=this.options,o=n.ticks.callback;if(o)return d(o,[t,e,i],this);const a=n.time.displayFormats,r=this._unit,l=this._majorUnit,h=r&&a[r],c=l&&a[l],u=i[e],f=l&&c&&u&&u.major;return this._adapter.format(t,s||(f?c:h))}generateTickLabels(t){let e,i,s;for(e=0,i=t.length;e0?a:1}getDataTimestamps(){let t,e,i=this._cache.data||[];if(i.length)return i;const s=this.getMatchingVisibleMetas();if(this._normalized&&s.length)return this._cache.data=s[0].controller.getAllParsedValues(this);for(t=0,e=s.length;t=t[r].pos&&e<=t[l].pos&&({lo:r,hi:l}=it(t,"pos",e)),({pos:s,time:o}=t[r]),({pos:n,time:a}=t[l])):(e>=t[r].time&&e<=t[l].time&&({lo:r,hi:l}=it(t,"time",e)),({time:s,pos:o}=t[r]),({time:n,pos:a}=t[l]));const h=n-s;return h?o+(a-o)*(e-s)/h:o}var jo=Object.freeze({__proto__:null,CategoryScale:class extends Js{static id="category";static defaults={ticks:{callback:po}};constructor(t){super(t),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(t){const e=this._addedLabels;if(e.length){const t=this.getLabels();for(const{index:i,label:s}of e)t[i]===s&&t.splice(i,1);this._addedLabels=[]}super.init(t)}parse(t,e){if(s(t))return null;const i=this.getLabels();return((t,e)=>null===t?null:J(Math.round(t),0,e))(e=isFinite(e)&&i[e]===t?e:go(i,t,l(e,t),this._addedLabels),i.length-1)}determineDataLimits(){const{minDefined:t,maxDefined:e}=this.getUserBounds();let{min:i,max:s}=this.getMinMax(!0);"ticks"===this.options.bounds&&(t||(i=0),e||(s=this.getLabels().length-1)),this.min=i,this.max=s}buildTicks(){const t=this.min,e=this.max,i=this.options.offset,s=[];let n=this.getLabels();n=0===t&&e===n.length-1?n:n.slice(t,e+1),this._valueRange=Math.max(n.length-(i?0:1),1),this._startValue=this.min-(i?.5:0);for(let i=t;i<=e;i++)s.push({value:i});return s}getLabelForValue(t){return po.call(this,t)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(t){return"number"!=typeof t&&(t=this.parse(t)),null===t?NaN:this.getPixelForDecimal((t-this._startValue)/this._valueRange)}getPixelForTick(t){const e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t].value)}getValueForPixel(t){return Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:bo,LogarithmicScale:ko,RadialLinearScale:Eo,TimeScale:No,TimeSeriesScale:class extends No{static id="timeseries";static defaults=No.defaults;constructor(t){super(t),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const t=this._getTimestampsForTable(),e=this._table=this.buildLookupTable(t);this._minPos=Ho(e,this.min),this._tableRange=Ho(e,this.max)-this._minPos,super.initOffsets(t)}buildLookupTable(t){const{min:e,max:i}=this,s=[],n=[];let o,a,r,l,h;for(o=0,a=t.length;o=e&&l<=i&&s.push(l);if(s.length<2)return[{time:e,pos:0},{time:i,pos:1}];for(o=0,a=s.length;ot-e))}_getTimestampsForTable(){let t=this._cache.all||[];if(t.length)return t;const e=this.getDataTimestamps(),i=this.getLabelTimestamps();return t=e.length&&i.length?this.normalize(e.concat(i)):e.length?e:i,t=this._cache.all=t,t}getDecimalForValue(t){return(Ho(this._table,t)-this._minPos)/this._tableRange}getValueForPixel(t){const e=this._offsets,i=this.getDecimalForPixel(t)/e.factor-e.end;return Ho(this._table,i*this._tableRange+this._minPos,!0)}}});const $o=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Yo=$o.map((t=>t.replace("rgb(","rgba(").replace(")",", 0.5)")));function Uo(t){return $o[t%$o.length]}function Xo(t){return Yo[t%Yo.length]}function qo(t){let e=0;return(i,s)=>{const n=t.getDatasetMeta(s).controller;n instanceof jn?e=function(t,e){return t.backgroundColor=t.data.map((()=>Uo(e++))),e}(i,e):n instanceof $n?e=function(t,e){return t.backgroundColor=t.data.map((()=>Xo(e++))),e}(i,e):n&&(e=function(t,e){return t.borderColor=Uo(e),t.backgroundColor=Xo(e),++e}(i,e))}}function Ko(t){let e;for(e in t)if(t[e].borderColor||t[e].backgroundColor)return!0;return!1}var Go={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(t,e,i){if(!i.enabled)return;const{data:{datasets:s},options:n}=t.config,{elements:o}=n,a=Ko(s)||(r=n)&&(r.borderColor||r.backgroundColor)||o&&Ko(o)||"rgba(0,0,0,0.1)"!==ue.borderColor||"rgba(0,0,0,0.1)"!==ue.backgroundColor;var r;if(!i.forceOverride&&a)return;const l=qo(t);s.forEach(l)}};function Zo(t){if(t._decimated){const e=t._data;delete t._decimated,delete t._data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,writable:!0,value:e})}}function Jo(t){t.data.datasets.forEach((t=>{Zo(t)}))}var Qo={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(t,e,i)=>{if(!i.enabled)return void Jo(t);const n=t.width;t.data.datasets.forEach(((e,o)=>{const{_data:a,indexAxis:r}=e,l=t.getDatasetMeta(o),h=a||e.data;if("y"===Pi([r,t.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=t.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(t.options.parsing)return;let{start:d,count:u}=function(t,e){const i=e.length;let s,n=0;const{iScale:o}=t,{min:a,max:r,minDefined:l,maxDefined:h}=o.getUserBounds();return l&&(n=J(it(e,o.axis,a).lo,0,i-1)),s=h?J(it(e,o.axis,r).hi+1,n,i)-n:i-n,{start:n,count:s}}(l,h);if(u<=(i.threshold||4*n))return void Zo(e);let f;switch(s(a)&&(e._data=h,delete e.data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(t){this._data=t}})),i.algorithm){case"lttb":f=function(t,e,i,s,n){const o=n.samples||s;if(o>=i)return t.slice(e,e+i);const a=[],r=(i-2)/(o-2);let l=0;const h=e+i-1;let c,d,u,f,g,p=e;for(a[l++]=t[p],c=0;cu&&(u=f,d=t[s],g=s);a[l++]=d,p=g}return a[l++]=t[h],a}(h,d,u,n,i);break;case"min-max":f=function(t,e,i,n){let o,a,r,l,h,c,d,u,f,g,p=0,m=0;const x=[],b=e+i-1,_=t[e].x,y=t[b].x-_;for(o=e;og&&(g=l,d=o),p=(m*p+a.x)/++m;else{const i=o-1;if(!s(c)&&!s(d)){const e=Math.min(c,d),s=Math.max(c,d);e!==u&&e!==i&&x.push({...t[e],x:p}),s!==u&&s!==i&&x.push({...t[s],x:p})}o>0&&i!==u&&x.push(t[i]),x.push(a),h=e,m=0,f=g=l,c=d=u=o}}return x}(h,d,u,n);break;default:throw new Error(`Unsupported decimation algorithm '${i.algorithm}'`)}e._decimated=f}))},destroy(t){Jo(t)}};function ta(t,e,i,s){if(s)return;let n=e[t],o=i[t];return"angle"===t&&(n=G(n),o=G(o)),{property:t,start:n,end:o}}function ea(t,e,i){for(;e>t;e--){const t=i[e];if(!isNaN(t.x)&&!isNaN(t.y))break}return e}function ia(t,e,i,s){return t&&e?s(t[i],e[i]):t?t[i]:e?e[i]:0}function sa(t,e){let i=[],s=!1;return n(t)?(s=!0,i=t):i=function(t,e){const{x:i=null,y:s=null}=t||{},n=e.points,o=[];return e.segments.forEach((({start:t,end:e})=>{e=ea(t,e,n);const a=n[t],r=n[e];null!==s?(o.push({x:a.x,y:s}),o.push({x:r.x,y:s})):null!==i&&(o.push({x:i,y:a.y}),o.push({x:i,y:r.y}))})),o}(t,e),i.length?new no({points:i,options:{tension:0},_loop:s,_fullLoop:s}):null}function na(t){return t&&!1!==t.fill}function oa(t,e,i){let s=t[e].fill;const n=[e];let o;if(!i)return s;for(;!1!==s&&-1===n.indexOf(s);){if(!a(s))return s;if(o=t[s],!o)return!1;if(o.visible)return s;n.push(s),s=o.fill}return!1}function aa(t,e,i){const s=function(t){const e=t.options,i=e.fill;let s=l(i&&i.target,i);void 0===s&&(s=!!e.backgroundColor);if(!1===s||null===s)return!1;if(!0===s)return"origin";return s}(t);if(o(s))return!isNaN(s.value)&&s;let n=parseFloat(s);return a(n)&&Math.floor(n)===n?function(t,e,i,s){"-"!==t&&"+"!==t||(i=e+i);if(i===e||i<0||i>=s)return!1;return i}(s[0],e,n,i):["origin","start","end","stack","shape"].indexOf(s)>=0&&s}function ra(t,e,i){const s=[];for(let n=0;n=0;--e){const i=n[e].$filler;i&&(i.line.updateControlPoints(o,i.axis),s&&i.fill&&da(t.ctx,i,o))}},beforeDatasetsDraw(t,e,i){if("beforeDatasetsDraw"!==i.drawTime)return;const s=t.getSortedVisibleDatasetMetas();for(let e=s.length-1;e>=0;--e){const i=s[e].$filler;na(i)&&da(t.ctx,i,t.chartArea)}},beforeDatasetDraw(t,e,i){const s=e.meta.$filler;na(s)&&"beforeDatasetDraw"===i.drawTime&&da(t.ctx,s,t.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const xa=(t,e)=>{let{boxHeight:i=e,boxWidth:s=e}=t;return t.usePointStyle&&(i=Math.min(i,e),s=t.pointStyleWidth||Math.min(s,e)),{boxWidth:s,boxHeight:i,itemHeight:Math.max(e,i)}};class ba extends Hs{constructor(t){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e,i){this.maxWidth=t,this.maxHeight=e,this._margins=i,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const t=this.options.labels||{};let e=d(t.generateLabels,[this.chart],this)||[];t.filter&&(e=e.filter((e=>t.filter(e,this.chart.data)))),t.sort&&(e=e.sort(((e,i)=>t.sort(e,i,this.chart.data)))),this.options.reverse&&e.reverse(),this.legendItems=e}fit(){const{options:t,ctx:e}=this;if(!t.display)return void(this.width=this.height=0);const i=t.labels,s=Si(i.font),n=s.size,o=this._computeTitleHeight(),{boxWidth:a,itemHeight:r}=xa(i,n);let l,h;e.font=s.string,this.isHorizontal()?(l=this.maxWidth,h=this._fitRows(o,n,a,r)+10):(h=this.maxHeight,l=this._fitCols(o,s,a,r)+10),this.width=Math.min(l,t.maxWidth||this.maxWidth),this.height=Math.min(h,t.maxHeight||this.maxHeight)}_fitRows(t,e,i,s){const{ctx:n,maxWidth:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.lineWidths=[0],h=s+a;let c=t;n.textAlign="left",n.textBaseline="middle";let d=-1,u=-h;return this.legendItems.forEach(((t,f)=>{const g=i+e/2+n.measureText(t.text).width;(0===f||l[l.length-1]+g+2*a>o)&&(c+=h,l[l.length-(f>0?0:1)]=0,u+=h,d++),r[f]={left:0,top:u,row:d,width:g,height:s},l[l.length-1]+=g+a})),c}_fitCols(t,e,i,s){const{ctx:n,maxHeight:o,options:{labels:{padding:a}}}=this,r=this.legendHitBoxes=[],l=this.columnSizes=[],h=o-t;let c=a,d=0,u=0,f=0,g=0;return this.legendItems.forEach(((t,o)=>{const{itemWidth:p,itemHeight:m}=function(t,e,i,s,n){const o=function(t,e,i,s){let n=t.text;n&&"string"!=typeof n&&(n=n.reduce(((t,e)=>t.length>e.length?t:e)));return e+i.size/2+s.measureText(n).width}(s,t,e,i),a=function(t,e,i){let s=t;"string"!=typeof e.text&&(s=_a(e,i));return s}(n,s,e.lineHeight);return{itemWidth:o,itemHeight:a}}(i,e,n,t,s);o>0&&u+m+2*a>h&&(c+=d+a,l.push({width:d,height:u}),f+=d+a,g++,d=u=0),r[o]={left:f,top:u,col:g,width:p,height:m},d=Math.max(d,p),u+=m+a})),c+=d,l.push({width:d,height:u}),c}adjustHitBoxes(){if(!this.options.display)return;const t=this._computeTitleHeight(),{legendHitBoxes:e,options:{align:i,labels:{padding:s},rtl:n}}=this,o=Oi(n,this.left,this.width);if(this.isHorizontal()){let n=0,a=ft(i,this.left+s,this.right-this.lineWidths[n]);for(const r of e)n!==r.row&&(n=r.row,a=ft(i,this.left+s,this.right-this.lineWidths[n])),r.top+=this.top+t+s,r.left=o.leftForLtr(o.x(a),r.width),a+=r.width+s}else{let n=0,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height);for(const r of e)r.col!==n&&(n=r.col,a=ft(i,this.top+t+s,this.bottom-this.columnSizes[n].height)),r.top=a,r.left+=this.left+s,r.left=o.leftForLtr(o.x(r.left),r.width),a+=r.height+s}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const t=this.ctx;Ie(t,this),this._draw(),ze(t)}}_draw(){const{options:t,columnSizes:e,lineWidths:i,ctx:s}=this,{align:n,labels:o}=t,a=ue.color,r=Oi(t.rtl,this.left,this.width),h=Si(o.font),{padding:c}=o,d=h.size,u=d/2;let f;this.drawTitle(),s.textAlign=r.textAlign("left"),s.textBaseline="middle",s.lineWidth=.5,s.font=h.string;const{boxWidth:g,boxHeight:p,itemHeight:m}=xa(o,d),x=this.isHorizontal(),b=this._computeTitleHeight();f=x?{x:ft(n,this.left+c,this.right-i[0]),y:this.top+c+b,line:0}:{x:this.left+c,y:ft(n,this.top+b+c,this.bottom-e[0].height),line:0},Ai(this.ctx,t.textDirection);const _=m+c;this.legendItems.forEach(((y,v)=>{s.strokeStyle=y.fontColor,s.fillStyle=y.fontColor;const M=s.measureText(y.text).width,w=r.textAlign(y.textAlign||(y.textAlign=o.textAlign)),k=g+u+M;let S=f.x,P=f.y;r.setWidth(this.width),x?v>0&&S+k+c>this.right&&(P=f.y+=_,f.line++,S=f.x=ft(n,this.left+c,this.right-i[f.line])):v>0&&P+_>this.bottom&&(S=f.x=S+e[f.line].width+c,f.line++,P=f.y=ft(n,this.top+b+c,this.bottom-e[f.line].height));if(function(t,e,i){if(isNaN(g)||g<=0||isNaN(p)||p<0)return;s.save();const n=l(i.lineWidth,1);if(s.fillStyle=l(i.fillStyle,a),s.lineCap=l(i.lineCap,"butt"),s.lineDashOffset=l(i.lineDashOffset,0),s.lineJoin=l(i.lineJoin,"miter"),s.lineWidth=n,s.strokeStyle=l(i.strokeStyle,a),s.setLineDash(l(i.lineDash,[])),o.usePointStyle){const a={radius:p*Math.SQRT2/2,pointStyle:i.pointStyle,rotation:i.rotation,borderWidth:n},l=r.xPlus(t,g/2);Ee(s,a,l,e+u,o.pointStyleWidth&&g)}else{const o=e+Math.max((d-p)/2,0),a=r.leftForLtr(t,g),l=wi(i.borderRadius);s.beginPath(),Object.values(l).some((t=>0!==t))?He(s,{x:a,y:o,w:g,h:p,radius:l}):s.rect(a,o,g,p),s.fill(),0!==n&&s.stroke()}s.restore()}(r.x(S),P,y),S=gt(w,S+g+u,x?S+k:this.right,t.rtl),function(t,e,i){Ne(s,i.text,t,e+m/2,h,{strikethrough:i.hidden,textAlign:r.textAlign(i.textAlign)})}(r.x(S),P,y),x)f.x+=k+c;else if("string"!=typeof y.text){const t=h.lineHeight;f.y+=_a(y,t)+c}else f.y+=_})),Ti(this.ctx,t.textDirection)}drawTitle(){const t=this.options,e=t.title,i=Si(e.font),s=ki(e.padding);if(!e.display)return;const n=Oi(t.rtl,this.left,this.width),o=this.ctx,a=e.position,r=i.size/2,l=s.top+r;let h,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),h=this.top+l,c=ft(t.align,c,this.right-d);else{const e=this.columnSizes.reduce(((t,e)=>Math.max(t,e.height)),0);h=l+ft(t.align,this.top,this.bottom-e-t.labels.padding-this._computeTitleHeight())}const u=ft(a,c,c+d);o.textAlign=n.textAlign(ut(a)),o.textBaseline="middle",o.strokeStyle=e.color,o.fillStyle=e.color,o.font=i.string,Ne(o,e.text,u,h,i)}_computeTitleHeight(){const t=this.options.title,e=Si(t.font),i=ki(t.padding);return t.display?e.lineHeight+i.height:0}_getLegendItemAt(t,e){let i,s,n;if(tt(t,this.left,this.right)&&tt(e,this.top,this.bottom))for(n=this.legendHitBoxes,i=0;it.chart.options.color,boxWidth:40,padding:10,generateLabels(t){const e=t.data.datasets,{labels:{usePointStyle:i,pointStyle:s,textAlign:n,color:o,useBorderRadius:a,borderRadius:r}}=t.legend.options;return t._getSortedDatasetMetas().map((t=>{const l=t.controller.getStyle(i?0:void 0),h=ki(l.borderWidth);return{text:e[t.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!t.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(h.width+h.height)/4,strokeStyle:l.borderColor,pointStyle:s||l.pointStyle,rotation:l.rotation,textAlign:n||l.textAlign,borderRadius:a&&(r||l.borderRadius),datasetIndex:t.index}}),this)}},title:{color:t=>t.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:t=>!t.startsWith("on"),labels:{_scriptable:t=>!["generateLabels","filter","sort"].includes(t)}}};class va extends Hs{constructor(t){super(),this.chart=t.chart,this.options=t.options,this.ctx=t.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(t,e){const i=this.options;if(this.left=0,this.top=0,!i.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=t,this.height=this.bottom=e;const s=n(i.text)?i.text.length:1;this._padding=ki(i.padding);const o=s*Si(i.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const t=this.options.position;return"top"===t||"bottom"===t}_drawArgs(t){const{top:e,left:i,bottom:s,right:n,options:o}=this,a=o.align;let r,l,h,c=0;return this.isHorizontal()?(l=ft(a,i,n),h=e+t,r=n-i):("left"===o.position?(l=i+t,h=ft(a,s,e),c=-.5*C):(l=n-t,h=ft(a,e,s),c=.5*C),r=s-e),{titleX:l,titleY:h,maxWidth:r,rotation:c}}draw(){const t=this.ctx,e=this.options;if(!e.display)return;const i=Si(e.font),s=i.lineHeight/2+this._padding.top,{titleX:n,titleY:o,maxWidth:a,rotation:r}=this._drawArgs(s);Ne(t,e.text,0,0,i,{color:e.color,maxWidth:a,rotation:r,textAlign:ut(e.align),textBaseline:"middle",translation:[n,o]})}}var Ma={id:"title",_element:va,start(t,e,i){!function(t,e){const i=new va({ctx:t.ctx,options:e,chart:t});as.configure(t,i,e),as.addBox(t,i),t.titleBlock=i}(t,i)},stop(t){const e=t.titleBlock;as.removeBox(t,e),delete t.titleBlock},beforeUpdate(t,e,i){const s=t.titleBlock;as.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const wa=new WeakMap;var ka={id:"subtitle",start(t,e,i){const s=new va({ctx:t.ctx,options:i,chart:t});as.configure(t,s,i),as.addBox(t,s),wa.set(t,s)},stop(t){as.removeBox(t,wa.get(t)),wa.delete(t)},beforeUpdate(t,e,i){const s=wa.get(t);as.configure(t,s,i),s.options=i},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const Sa={average(t){if(!t.length)return!1;let e,i,s=new Set,n=0,o=0;for(e=0,i=t.length;et+e))/s.size,y:n/o}},nearest(t,e){if(!t.length)return!1;let i,s,n,o=e.x,a=e.y,r=Number.POSITIVE_INFINITY;for(i=0,s=t.length;i-1?t.split("\n"):t}function Ca(t,e){const{element:i,datasetIndex:s,index:n}=e,o=t.getDatasetMeta(s).controller,{label:a,value:r}=o.getLabelAndValue(n);return{chart:t,label:a,parsed:o.getParsed(n),raw:t.data.datasets[s].data[n],formattedValue:r,dataset:o.getDataset(),dataIndex:n,datasetIndex:s,element:i}}function Oa(t,e){const i=t.chart.ctx,{body:s,footer:n,title:o}=t,{boxWidth:a,boxHeight:r}=e,l=Si(e.bodyFont),h=Si(e.titleFont),c=Si(e.footerFont),d=o.length,f=n.length,g=s.length,p=ki(e.padding);let m=p.height,x=0,b=s.reduce(((t,e)=>t+e.before.length+e.lines.length+e.after.length),0);if(b+=t.beforeBody.length+t.afterBody.length,d&&(m+=d*h.lineHeight+(d-1)*e.titleSpacing+e.titleMarginBottom),b){m+=g*(e.displayColors?Math.max(r,l.lineHeight):l.lineHeight)+(b-g)*l.lineHeight+(b-1)*e.bodySpacing}f&&(m+=e.footerMarginTop+f*c.lineHeight+(f-1)*e.footerSpacing);let _=0;const y=function(t){x=Math.max(x,i.measureText(t).width+_)};return i.save(),i.font=h.string,u(t.title,y),i.font=l.string,u(t.beforeBody.concat(t.afterBody),y),_=e.displayColors?a+2+e.boxPadding:0,u(s,(t=>{u(t.before,y),u(t.lines,y),u(t.after,y)})),_=0,i.font=c.string,u(t.footer,y),i.restore(),x+=p.width,{width:x,height:m}}function Aa(t,e,i,s){const{x:n,width:o}=i,{width:a,chartArea:{left:r,right:l}}=t;let h="center";return"center"===s?h=n<=(r+l)/2?"left":"right":n<=o/2?h="left":n>=a-o/2&&(h="right"),function(t,e,i,s){const{x:n,width:o}=s,a=i.caretSize+i.caretPadding;return"left"===t&&n+o+a>e.width||"right"===t&&n-o-a<0||void 0}(h,t,e,i)&&(h="center"),h}function Ta(t,e,i){const s=i.yAlign||e.yAlign||function(t,e){const{y:i,height:s}=e;return it.height-s/2?"bottom":"center"}(t,i);return{xAlign:i.xAlign||e.xAlign||Aa(t,e,i,s),yAlign:s}}function La(t,e,i,s){const{caretSize:n,caretPadding:o,cornerRadius:a}=t,{xAlign:r,yAlign:l}=i,h=n+o,{topLeft:c,topRight:d,bottomLeft:u,bottomRight:f}=wi(a);let g=function(t,e){let{x:i,width:s}=t;return"right"===e?i-=s:"center"===e&&(i-=s/2),i}(e,r);const p=function(t,e,i){let{y:s,height:n}=t;return"top"===e?s+=i:s-="bottom"===e?n+i:n/2,s}(e,l,h);return"center"===l?"left"===r?g+=h:"right"===r&&(g-=h):"left"===r?g-=Math.max(c,u)+n:"right"===r&&(g+=Math.max(d,f)+n),{x:J(g,0,s.width-e.width),y:J(p,0,s.height-e.height)}}function Ea(t,e,i){const s=ki(i.padding);return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-s.right:t.x+s.left}function Ra(t){return Pa([],Da(t))}function Ia(t,e){const i=e&&e.dataset&&e.dataset.tooltip&&e.dataset.tooltip.callbacks;return i?t.override(i):t}const za={beforeTitle:e,title(t){if(t.length>0){const e=t[0],i=e.chart.data.labels,s=i?i.length:0;if(this&&this.options&&"dataset"===this.options.mode)return e.dataset.label||"";if(e.label)return e.label;if(s>0&&e.dataIndex{const e={before:[],lines:[],after:[]},n=Ia(i,t);Pa(e.before,Da(Fa(n,"beforeLabel",this,t))),Pa(e.lines,Fa(n,"label",this,t)),Pa(e.after,Da(Fa(n,"afterLabel",this,t))),s.push(e)})),s}getAfterBody(t,e){return Ra(Fa(e.callbacks,"afterBody",this,t))}getFooter(t,e){const{callbacks:i}=e,s=Fa(i,"beforeFooter",this,t),n=Fa(i,"footer",this,t),o=Fa(i,"afterFooter",this,t);let a=[];return a=Pa(a,Da(s)),a=Pa(a,Da(n)),a=Pa(a,Da(o)),a}_createItems(t){const e=this._active,i=this.chart.data,s=[],n=[],o=[];let a,r,l=[];for(a=0,r=e.length;at.filter(e,s,n,i)))),t.itemSort&&(l=l.sort(((e,s)=>t.itemSort(e,s,i)))),u(l,(e=>{const i=Ia(t.callbacks,e);s.push(Fa(i,"labelColor",this,e)),n.push(Fa(i,"labelPointStyle",this,e)),o.push(Fa(i,"labelTextColor",this,e))})),this.labelColors=s,this.labelPointStyles=n,this.labelTextColors=o,this.dataPoints=l,l}update(t,e){const i=this.options.setContext(this.getContext()),s=this._active;let n,o=[];if(s.length){const t=Sa[i.position].call(this,s,this._eventPosition);o=this._createItems(i),this.title=this.getTitle(o,i),this.beforeBody=this.getBeforeBody(o,i),this.body=this.getBody(o,i),this.afterBody=this.getAfterBody(o,i),this.footer=this.getFooter(o,i);const e=this._size=Oa(this,i),a=Object.assign({},t,e),r=Ta(this.chart,i,a),l=La(i,a,r,this.chart);this.xAlign=r.xAlign,this.yAlign=r.yAlign,n={opacity:1,x:l.x,y:l.y,width:e.width,height:e.height,caretX:t.x,caretY:t.y}}else 0!==this.opacity&&(n={opacity:0});this._tooltipItems=o,this.$context=void 0,n&&this._resolveAnimations().update(this,n),t&&i.external&&i.external.call(this,{chart:this.chart,tooltip:this,replay:e})}drawCaret(t,e,i,s){const n=this.getCaretPosition(t,i,s);e.lineTo(n.x1,n.y1),e.lineTo(n.x2,n.y2),e.lineTo(n.x3,n.y3)}getCaretPosition(t,e,i){const{xAlign:s,yAlign:n}=this,{caretSize:o,cornerRadius:a}=i,{topLeft:r,topRight:l,bottomLeft:h,bottomRight:c}=wi(a),{x:d,y:u}=t,{width:f,height:g}=e;let p,m,x,b,_,y;return"center"===n?(_=u+g/2,"left"===s?(p=d,m=p-o,b=_+o,y=_-o):(p=d+f,m=p+o,b=_-o,y=_+o),x=p):(m="left"===s?d+Math.max(r,h)+o:"right"===s?d+f-Math.max(l,c)-o:this.caretX,"top"===n?(b=u,_=b-o,p=m-o,x=m+o):(b=u+g,_=b+o,p=m+o,x=m-o),y=b),{x1:p,x2:m,x3:x,y1:b,y2:_,y3:y}}drawTitle(t,e,i){const s=this.title,n=s.length;let o,a,r;if(n){const l=Oi(i.rtl,this.x,this.width);for(t.x=Ea(this,i.titleAlign,i),e.textAlign=l.textAlign(i.titleAlign),e.textBaseline="middle",o=Si(i.titleFont),a=i.titleSpacing,e.fillStyle=i.titleColor,e.font=o.string,r=0;r0!==t))?(t.beginPath(),t.fillStyle=n.multiKeyBackground,He(t,{x:e,y:g,w:h,h:l,radius:r}),t.fill(),t.stroke(),t.fillStyle=a.backgroundColor,t.beginPath(),He(t,{x:i,y:g+1,w:h-2,h:l-2,radius:r}),t.fill()):(t.fillStyle=n.multiKeyBackground,t.fillRect(e,g,h,l),t.strokeRect(e,g,h,l),t.fillStyle=a.backgroundColor,t.fillRect(i,g+1,h-2,l-2))}t.fillStyle=this.labelTextColors[i]}drawBody(t,e,i){const{body:s}=this,{bodySpacing:n,bodyAlign:o,displayColors:a,boxHeight:r,boxWidth:l,boxPadding:h}=i,c=Si(i.bodyFont);let d=c.lineHeight,f=0;const g=Oi(i.rtl,this.x,this.width),p=function(i){e.fillText(i,g.x(t.x+f),t.y+d/2),t.y+=d+n},m=g.textAlign(o);let x,b,_,y,v,M,w;for(e.textAlign=o,e.textBaseline="middle",e.font=c.string,t.x=Ea(this,m,i),e.fillStyle=i.bodyColor,u(this.beforeBody,p),f=a&&"right"!==m?"center"===o?l/2+h:l+2+h:0,y=0,M=s.length;y0&&e.stroke()}_updateAnimationTarget(t){const e=this.chart,i=this.$animations,s=i&&i.x,n=i&&i.y;if(s||n){const i=Sa[t.position].call(this,this._active,this._eventPosition);if(!i)return;const o=this._size=Oa(this,t),a=Object.assign({},i,this._size),r=Ta(e,t,a),l=La(t,a,r,e);s._to===l.x&&n._to===l.y||(this.xAlign=r.xAlign,this.yAlign=r.yAlign,this.width=o.width,this.height=o.height,this.caretX=i.x,this.caretY=i.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(t){const e=this.options.setContext(this.getContext());let i=this.opacity;if(!i)return;this._updateAnimationTarget(e);const s={width:this.width,height:this.height},n={x:this.x,y:this.y};i=Math.abs(i)<.001?0:i;const o=ki(e.padding),a=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;e.enabled&&a&&(t.save(),t.globalAlpha=i,this.drawBackground(n,t,s,e),Ai(t,e.textDirection),n.y+=o.top,this.drawTitle(n,t,e),this.drawBody(n,t,e),this.drawFooter(n,t,e),Ti(t,e.textDirection),t.restore())}getActiveElements(){return this._active||[]}setActiveElements(t,e){const i=this._active,s=t.map((({datasetIndex:t,index:e})=>{const i=this.chart.getDatasetMeta(t);if(!i)throw new Error("Cannot find a dataset at index "+t);return{datasetIndex:t,element:i.data[e],index:e}})),n=!f(i,s),o=this._positionChanged(s,e);(n||o)&&(this._active=s,this._eventPosition=e,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(t,e,i=!0){if(e&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const s=this.options,n=this._active||[],o=this._getActiveElements(t,n,e,i),a=this._positionChanged(o,t),r=e||!f(o,n)||a;return r&&(this._active=o,(s.enabled||s.external)&&(this._eventPosition={x:t.x,y:t.y},this.update(!0,e))),r}_getActiveElements(t,e,i,s){const n=this.options;if("mouseout"===t.type)return[];if(!s)return e.filter((t=>this.chart.data.datasets[t.datasetIndex]&&void 0!==this.chart.getDatasetMeta(t.datasetIndex).controller.getParsed(t.index)));const o=this.chart.getElementsAtEventForMode(t,n.mode,n,i);return n.reverse&&o.reverse(),o}_positionChanged(t,e){const{caretX:i,caretY:s,options:n}=this,o=Sa[n.position].call(this,t,e);return!1!==o&&(i!==o.x||s!==o.y)}}var Ba={id:"tooltip",_element:Va,positioners:Sa,afterInit(t,e,i){i&&(t.tooltip=new Va({chart:t,options:i}))},beforeUpdate(t,e,i){t.tooltip&&t.tooltip.initialize(i)},reset(t,e,i){t.tooltip&&t.tooltip.initialize(i)},afterDraw(t){const e=t.tooltip;if(e&&e._willRender()){const i={tooltip:e};if(!1===t.notifyPlugins("beforeTooltipDraw",{...i,cancelable:!0}))return;e.draw(t.ctx),t.notifyPlugins("afterTooltipDraw",i)}},afterEvent(t,e){if(t.tooltip){const i=e.replay;t.tooltip.handleEvent(e.event,i,e.inChartArea)&&(e.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(t,e)=>e.bodyFont.size,boxWidth:(t,e)=>e.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:za},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:t=>"filter"!==t&&"itemSort"!==t&&"external"!==t,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return An.register(Yn,jo,fo,t),An.helpers={...Wi},An._adapters=Rn,An.Animation=Cs,An.Animations=Os,An.animator=bt,An.controllers=en.controllers.items,An.DatasetController=Ns,An.Element=Hs,An.elements=fo,An.Interaction=Xi,An.layouts=as,An.platforms=Ss,An.Scale=Js,An.Ticks=ae,Object.assign(An,Yn,jo,fo,t,Ss),An.Chart=An,"undefined"!=typeof window&&(window.Chart=An),An})); +//# sourceMappingURL=chart.umd.js.map diff --git a/assets/js/chartUtils.js b/assets/js/chartUtils.js new file mode 100644 index 0000000..895ff34 --- /dev/null +++ b/assets/js/chartUtils.js @@ -0,0 +1,293 @@ +function barChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) { + const canvas = document.getElementById('bar_chart'+id) + const ctx = canvas.getContext("2d"); + + data = data.map((item) => DecimalPrecision.round(item, 2)); + + // Gradient + var gradient = ctx.createLinearGradient(0, 0, 0, 500); + gradient.addColorStop(0, '#f4a260'); + gradient.addColorStop(1, '#2ec4b6'); + + // Data + var displayData = { + labels: labels, + datasets: [ + { + label: tooltip, + data: data, + backgroundColor: gradient, + } + ] + }; + + // Options + var options = { + responsive: true, + + scales: { + x: { + display: true, + text: scale_label_x, + }, + y: { + display: true, + text: scale_label_y, + beginAtZero: true + } + }, + + plugins: { + title: { + display: true, + text: title, + font: { + size: 20, + } + } + }, + + }; + + var config = { + type: 'bar', + data: displayData, + options: options + }; + + new Chart(ctx, config); +} + +function barLineChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) { + const canvas = document.getElementById('bar_line_chart'+id) + const ctx = canvas.getContext("2d"); + + // Gradient + const gradient = ctx.createLinearGradient(0, 0, 0, 500); + gradient.addColorStop(0, '#f4a260'); + gradient.addColorStop(1, '#2ec4b6'); + + const sum = data.reduce((partialSum, a) => partialSum + a, 0); + const percentage = data.map((item) => DecimalPrecision.round(item/sum*100, 2)); + var percentageTick = 100; + var percentageTickSize = 20; + + // Data + const displayData = { + labels: labels, + datasets: [ + { + label: "Percentage", + data: percentage, + borderColor: '#E0E1DD', + backgroundColor: '#2ec4b6', + yAxisID: 'y1', + type: 'line', + }, + { + label: tooltip, + data: data, + backgroundColor: gradient, + yAxisID: 'y', + }, + + ] + }; + + // Options + const options = { + responsive: true, + + scales: { + x: { + display: true, + text: scale_label_x, + }, + y: { + display: true, + text: scale_label_y, + beginAtZero: true, + max: Math.max.apply(null, data) + 1, + }, + + y1: { + display: true, + position: 'right', + beginAtZero: true, + max: percentageTick, + ticks: { + stepSize: percentageTickSize, + }, + }, + }, + + plugins: { + title: { + display: true, + text: title, + font: { + size: 20, + } + } + }, + + }; + + const config = { + type: 'bar', + data: displayData, + options: options + }; + + let barlinechart = new Chart(ctx, config); + + // Actions + const actions = [ + { + name: "Toggle Tick", + handler(chart) { + if (percentageTick == 100 ) { + percentageTick = Math.trunc(Math.max.apply(null, percentage) + 1); + percentageTickSize = Math.trunc(percentageTick / 5); + } + else { + percentageTick = 100; + percentageTickSize = 20; + } + barlinechart.options.scales.y1.max = percentageTick; + barlinechart.options.scales.y1.ticks.stepSize = percentageTickSize; + chart.update(); + } + } + ]; + + actions.forEach((a, i) => { + let button = document.createElement("button"); + button.id = "button"+i; + button.innerText = a.name; + button.onclick = () => a.handler(barlinechart); + document.querySelector(".button_row").appendChild(button); + }); +} + +function pieChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) { + const canvas = document.getElementById('pie_chart'+id) + const ctx = canvas.getContext("2d"); + + // Data + var displayData = { + labels: labels, + datasets: [ + { + label: tooltip, + data: data, + backgroundColor: [ + '#f4a260', + '#e77f7a', + '#be6d8e', + '#856490', + '#4f597b', + '#2f4858', + ], + } + ] + }; + + // Options + var options = { + responsive: true, + }; + + var config = { + type: 'pie', + data: displayData, + options: options + }; + + new Chart(ctx, config); +} + +function doughnutChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) { + const canvas = document.getElementById('doughnut_chart'+id) + const ctx = canvas.getContext("2d"); + + // Data + var displayData = { + labels: labels, + datasets: [ + { + label: tooltip, + data: data, + backgroundColor: [ + '#f4a260', + '#e77f7a', + '#be6d8e', + '#856490', + '#4f597b', + '#2f4858', + ], + } + ] + }; + + // Options + var options = { + responsive: true, + }; + + var config = { + type: 'doughnut', + data: displayData, + options: options + }; + + new Chart(ctx, config); +} + +function polarChart(id, data, labels, tooltip, title, scale_label_x, scale_label_y) { + const canvas = document.getElementById('polar_chart'+id) + const ctx = canvas.getContext("2d"); + + // Data + var displayData = { + labels: labels, + datasets: [ + { + label: tooltip, + data: data, + backgroundColor: [ + '#f4a260', + '#e77f7a', + '#be6d8e', + '#856490', + '#4f597b', + '#2f4858', + ], + } + ] + }; + + // Options + var options = { + responsive: true, + + scales: { + x: { + border: { display: true }, + grid: { + display: false, + drawOnChartArea: true, + drawTicks: false, + }, + }, + }, + }; + + var config = { + type: 'polarArea', + data: displayData, + options: config, + }; + + new Chart(ctx, config); +} diff --git a/assets/js/htmx.min.js b/assets/js/htmx.min.js new file mode 100644 index 0000000..59937d7 --- /dev/null +++ b/assets/js/htmx.min.js @@ -0,0 +1 @@ +var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.4"};Q.onLoad=j;Q.process=kt;Q.on=ye;Q.off=be;Q.trigger=he;Q.ajax=Rn;Q.find=u;Q.findAll=x;Q.closest=g;Q.remove=z;Q.addClass=K;Q.removeClass=G;Q.toggleClass=W;Q.takeClass=Z;Q.swap=$e;Q.defineExtension=Fn;Q.removeExtension=Bn;Q.logAll=V;Q.logNone=_;Q.parseInterval=d;Q._=e;const n={addTriggerHandler:St,bodyContains:le,canAccessLocalStorage:B,findThisElement:Se,filterValues:hn,swap:$e,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:o,getExpressionVars:En,getHeaders:fn,getInputValues:cn,getInternalData:ie,getSwapSpecification:gn,getTriggerSpecs:st,getTarget:Ee,makeFragment:P,mergeObjects:ce,makeSettleInfo:xn,oobSwap:He,querySelectorExt:ae,settleImmediately:Kt,shouldCancel:ht,triggerEvent:he,triggerErrorEvent:fe,withExtensions:Ft};const r=["get","post","put","delete","patch"];const H=r.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function c(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function m(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function o(e,t){while(e&&!t(e)){e=c(e)}return e||null}function i(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;o(t,function(e){return!!(r=i(t,ue(e),n))});if(r!=="unset"){return r}}function h(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function T(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function q(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function L(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function A(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function N(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function I(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(N(e)){const t=A(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){O(e)}finally{e.remove()}}})}function P(e){const t=e.replace(/]*)?>[\s\S]*?<\/head>/i,"");const n=T(t);let r;if(n==="html"){r=new DocumentFragment;const i=q(e);L(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=q(t);L(r,i.body);r.title=i.title}else{const i=q('");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){I(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}return r}function oe(e){if(e){e()}}function t(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function k(e){return typeof e==="function"}function D(e){return t(e,"Object")}function ie(e){const t="htmx-internal-data";let n=e[t];if(!n){n=e[t]={}}return n}function M(t){const n=[];if(t){for(let e=0;e=0}function le(e){return e.getRootNode({composed:true})===document}function F(e){return e.trim().split(/\s+/)}function ce(e,t){for(const n in t){if(t.hasOwnProperty(n)){e[n]=t[n]}}return e}function S(e){try{return JSON.parse(e)}catch(e){O(e);return null}}function B(){const e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function U(t){try{const e=new URL(t);if(e){t=e.pathname+e.search}if(!/^\/$/.test(t)){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function e(e){return vn(ne().body,function(){return eval(e)})}function j(t){const e=Q.on("htmx:load",function(e){t(e.detail.elt)});return e}function V(){Q.logger=function(e,t,n){if(console){console.log(t,e,n)}}}function _(){Q.logger=null}function u(e,t){if(typeof e!=="string"){return e.querySelector(t)}else{return u(ne(),e)}}function x(e,t){if(typeof e!=="string"){return e.querySelectorAll(t)}else{return x(ne(),e)}}function E(){return window}function z(e,t){e=y(e);if(t){E().setTimeout(function(){z(e);e=null},t)}else{c(e).removeChild(e)}}function ue(e){return e instanceof Element?e:null}function $(e){return e instanceof HTMLElement?e:null}function J(e){return typeof e==="string"?e:null}function f(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function K(e,t,n){e=ue(y(e));if(!e){return}if(n){E().setTimeout(function(){K(e,t);e=null},n)}else{e.classList&&e.classList.add(t)}}function G(e,t,n){let r=ue(y(e));if(!r){return}if(n){E().setTimeout(function(){G(r,t);r=null},n)}else{if(r.classList){r.classList.remove(t);if(r.classList.length===0){r.removeAttribute("class")}}}}function W(e,t){e=y(e);e.classList.toggle(t)}function Z(e,t){e=y(e);se(e.parentElement.children,function(e){G(e,t)});K(ue(e),t)}function g(e,t){e=ue(y(e));if(e&&e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&ue(c(e)));return null}}function l(e,t){return e.substring(0,t.length)===t}function Y(e,t){return e.substring(e.length-t.length)===t}function ge(e){const t=e.trim();if(l(t,"<")&&Y(t,"/>")){return t.substring(1,t.length-2)}else{return t}}function p(t,r,n){if(r.indexOf("global ")===0){return p(t,r.slice(7),true)}t=y(t);const o=[];{let t=0;let n=0;for(let e=0;e"){t--}}if(n0){const r=ge(o.shift());let e;if(r.indexOf("closest ")===0){e=g(ue(t),ge(r.substr(8)))}else if(r.indexOf("find ")===0){e=u(f(t),ge(r.substr(5)))}else if(r==="next"||r==="nextElementSibling"){e=ue(t).nextElementSibling}else if(r.indexOf("next ")===0){e=pe(t,ge(r.substr(5)),!!n)}else if(r==="previous"||r==="previousElementSibling"){e=ue(t).previousElementSibling}else if(r.indexOf("previous ")===0){e=me(t,ge(r.substr(9)),!!n)}else if(r==="document"){e=document}else if(r==="window"){e=window}else if(r==="body"){e=document.body}else if(r==="root"){e=m(t,!!n)}else if(r==="host"){e=t.getRootNode().host}else{s.push(r)}if(e){i.push(e)}}if(s.length>0){const e=s.join(",");const c=f(m(t,!!n));i.push(...M(c.querySelectorAll(e)))}return i}var pe=function(t,e,n){const r=f(m(t,n)).querySelectorAll(e);for(let e=0;e=0;e--){const o=r[e];if(o.compareDocumentPosition(t)===Node.DOCUMENT_POSITION_FOLLOWING){return o}}};function ae(e,t){if(typeof e!=="string"){return p(e,t)[0]}else{return p(ne().body,e)[0]}}function y(e,t){if(typeof e==="string"){return u(f(t)||document,e)}else{return e}}function xe(e,t,n,r){if(k(t)){return{target:ne().body,event:J(e),listener:t,options:n}}else{return{target:y(e),event:J(t),listener:n,options:r}}}function ye(t,n,r,o){Vn(function(){const e=xe(t,n,r,o);e.target.addEventListener(e.event,e.listener,e.options)});const e=k(n);return e?n:r}function be(t,n,r){Vn(function(){const e=xe(t,n,r);e.target.removeEventListener(e.event,e.listener)});return k(n)?n:r}const ve=ne().createElement("output");function we(e,t){const n=re(e,t);if(n){if(n==="this"){return[Se(e,t)]}else{const r=p(e,n);if(r.length===0){O('The selector "'+n+'" on '+t+" returned no matches!");return[ve]}else{return r}}}}function Se(e,t){return ue(o(e,function(e){return te(ue(e),t)!=null}))}function Ee(e){const t=re(e,"hx-target");if(t){if(t==="this"){return Se(e,"hx-target")}else{return ae(e,t)}}else{const n=ie(e);if(n.boosted){return ne().body}else{return e}}}function Ce(t){const n=Q.config.attributesToSettle;for(let e=0;e0){s=e.substring(0,e.indexOf(":"));n=e.substring(e.indexOf(":")+1)}else{s=e}o.removeAttribute("hx-swap-oob");o.removeAttribute("data-hx-swap-oob");const r=p(t,n,false);if(r){se(r,function(e){let t;const n=o.cloneNode(true);t=ne().createDocumentFragment();t.appendChild(n);if(!Re(s,e)){t=f(n)}const r={shouldSwap:true,target:e,fragment:t};if(!he(e,"htmx:oobBeforeSwap",r))return;e=r.target;if(r.shouldSwap){qe(t);_e(s,e,e,t,i);Te()}se(i.elts,function(e){he(e,"htmx:oobAfterSwap",r)})});o.parentNode.removeChild(o)}else{o.parentNode.removeChild(o);fe(ne().body,"htmx:oobErrorNoTarget",{content:o})}return e}function Te(){const e=u("#--htmx-preserve-pantry--");if(e){for(const t of[...e.children]){const n=u("#"+t.id);n.parentNode.moveBefore(t,n);n.remove()}e.remove()}}function qe(e){se(x(e,"[hx-preserve], [data-hx-preserve]"),function(e){const t=te(e,"id");const n=ne().getElementById(t);if(n!=null){if(e.moveBefore){let e=u("#--htmx-preserve-pantry--");if(e==null){ne().body.insertAdjacentHTML("afterend","
");e=u("#--htmx-preserve-pantry--")}e.moveBefore(n,null)}else{e.parentNode.replaceChild(n,e)}}})}function Le(l,e,c){se(e.querySelectorAll("[id]"),function(t){const n=ee(t,"id");if(n&&n.length>0){const r=n.replace("'","\\'");const o=t.tagName.replace(":","\\:");const e=f(l);const i=e&&e.querySelector(o+"[id='"+r+"']");if(i&&i!==e){const s=t.cloneNode();Oe(t,i);c.tasks.push(function(){Oe(t,s)})}}})}function Ae(e){return function(){G(e,Q.config.addedClass);kt(ue(e));Ne(f(e));he(e,"htmx:load")}}function Ne(e){const t="[autofocus]";const n=$(h(e,t)?e:e.querySelector(t));if(n!=null){n.focus()}}function a(e,t,n,r){Le(e,n,r);while(n.childNodes.length>0){const o=n.firstChild;K(ue(o),Q.config.addedClass);e.insertBefore(o,t);if(o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE){r.tasks.push(Ae(o))}}}function Ie(e,t){let n=0;while(n0}function $e(e,t,r,o){if(!o){o={}}e=y(e);const i=o.contextElement?m(o.contextElement,false):ne();const n=document.activeElement;let s={};try{s={elt:n,start:n?n.selectionStart:null,end:n?n.selectionEnd:null}}catch(e){}const l=xn(e);if(r.swapStyle==="textContent"){e.textContent=t}else{let n=P(t);l.title=n.title;if(o.selectOOB){const u=o.selectOOB.split(",");for(let t=0;t0){E().setTimeout(c,r.settleDelay)}else{c()}}function Je(e,t,n){const r=e.getResponseHeader(t);if(r.indexOf("{")===0){const o=S(r);for(const i in o){if(o.hasOwnProperty(i)){let e=o[i];if(D(e)){n=e.target!==undefined?e.target:n}else{e={value:e}}he(n,i,e)}}}else{const s=r.split(",");for(let e=0;e0){const s=o[0];if(s==="]"){e--;if(e===0){if(n===null){t=t+"true"}o.shift();t+=")})";try{const l=vn(r,function(){return Function(t)()},function(){return true});l.source=t;return l}catch(e){fe(ne().body,"htmx:syntax:error",{error:e,source:t});return null}}}else if(s==="["){e++}if(tt(s,n,i)){t+="(("+i+"."+s+") ? ("+i+"."+s+") : (window."+s+"))"}else{t=t+s}n=o.shift()}}}function C(e,t){let n="";while(e.length>0&&!t.test(e[0])){n+=e.shift()}return n}function rt(e){let t;if(e.length>0&&Ye.test(e[0])){e.shift();t=C(e,Qe).trim();e.shift()}else{t=C(e,v)}return t}const ot="input, textarea, select";function it(e,t,n){const r=[];const o=et(t);do{C(o,w);const l=o.length;const c=C(o,/[,\[\s]/);if(c!==""){if(c==="every"){const u={trigger:"every"};C(o,w);u.pollInterval=d(C(o,/[,\[\s]/));C(o,w);var i=nt(e,o,"event");if(i){u.eventFilter=i}r.push(u)}else{const a={trigger:c};var i=nt(e,o,"event");if(i){a.eventFilter=i}C(o,w);while(o.length>0&&o[0]!==","){const f=o.shift();if(f==="changed"){a.changed=true}else if(f==="once"){a.once=true}else if(f==="consume"){a.consume=true}else if(f==="delay"&&o[0]===":"){o.shift();a.delay=d(C(o,v))}else if(f==="from"&&o[0]===":"){o.shift();if(Ye.test(o[0])){var s=rt(o)}else{var s=C(o,v);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();const h=rt(o);if(h.length>0){s+=" "+h}}}a.from=s}else if(f==="target"&&o[0]===":"){o.shift();a.target=rt(o)}else if(f==="throttle"&&o[0]===":"){o.shift();a.throttle=d(C(o,v))}else if(f==="queue"&&o[0]===":"){o.shift();a.queue=C(o,v)}else if(f==="root"&&o[0]===":"){o.shift();a[f]=rt(o)}else if(f==="threshold"&&o[0]===":"){o.shift();a[f]=C(o,v)}else{fe(e,"htmx:syntax:error",{token:o.shift()})}C(o,w)}r.push(a)}}if(o.length===l){fe(e,"htmx:syntax:error",{token:o.shift()})}C(o,w)}while(o[0]===","&&o.shift());if(n){n[t]=r}return r}function st(e){const t=te(e,"hx-trigger");let n=[];if(t){const r=Q.config.triggerSpecsCache;n=r&&r[t]||it(e,t,r)}if(n.length>0){return n}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"], input[type="submit"]')){return[{trigger:"click"}]}else if(h(e,ot)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function lt(e){ie(e).cancelled=true}function ct(e,t,n){const r=ie(e);r.timeout=E().setTimeout(function(){if(le(e)&&r.cancelled!==true){if(!gt(n,e,Mt("hx:poll:trigger",{triggerSpec:n,target:e}))){t(e)}ct(e,t,n)}},n.pollInterval)}function ut(e){return location.hostname===e.hostname&&ee(e,"href")&&ee(e,"href").indexOf("#")!==0}function at(e){return g(e,Q.config.disableSelector)}function ft(t,n,e){if(t instanceof HTMLAnchorElement&&ut(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"&&String(ee(t,"method")).toLowerCase()!=="dialog"){n.boosted=true;let r,o;if(t.tagName==="A"){r="get";o=ee(t,"href")}else{const i=ee(t,"method");r=i?i.toLowerCase():"get";o=ee(t,"action");if(o==null||o===""){o=ne().location.href}if(r==="get"&&o.includes("?")){o=o.replace(/\?[^#]+/,"")}}e.forEach(function(e){pt(t,function(e,t){const n=ue(e);if(at(n)){b(n);return}de(r,o,n,t)},n,e,true)})}}function ht(e,t){const n=ue(t);if(!n){return false}if(e.type==="submit"||e.type==="click"){if(n.tagName==="FORM"){return true}if(h(n,'input[type="submit"], button')&&(h(n,"[form]")||g(n,"form")!==null)){return true}if(n instanceof HTMLAnchorElement&&n.href&&(n.getAttribute("href")==="#"||n.getAttribute("href").indexOf("#")!==0)){return true}}return false}function dt(e,t){return ie(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function gt(e,t,n){const r=e.eventFilter;if(r){try{return r.call(t,n)!==true}catch(e){const o=r.source;fe(ne().body,"htmx:eventFilter:error",{error:e,source:o});return true}}return false}function pt(l,c,e,u,a){const f=ie(l);let t;if(u.from){t=p(l,u.from)}else{t=[l]}if(u.changed){if(!("lastValue"in f)){f.lastValue=new WeakMap}t.forEach(function(e){if(!f.lastValue.has(u)){f.lastValue.set(u,new WeakMap)}f.lastValue.get(u).set(e,e.value)})}se(t,function(i){const s=function(e){if(!le(l)){i.removeEventListener(u.trigger,s);return}if(dt(l,e)){return}if(a||ht(e,l)){e.preventDefault()}if(gt(u,l,e)){return}const t=ie(e);t.triggerSpec=u;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(l)<0){t.handledFor.push(l);if(u.consume){e.stopPropagation()}if(u.target&&e.target){if(!h(ue(e.target),u.target)){return}}if(u.once){if(f.triggeredOnce){return}else{f.triggeredOnce=true}}if(u.changed){const n=event.target;const r=n.value;const o=f.lastValue.get(u);if(o.has(n)&&o.get(n)===r){return}o.set(n,r)}if(f.delayed){clearTimeout(f.delayed)}if(f.throttle){return}if(u.throttle>0){if(!f.throttle){he(l,"htmx:trigger");c(l,e);f.throttle=E().setTimeout(function(){f.throttle=null},u.throttle)}}else if(u.delay>0){f.delayed=E().setTimeout(function(){he(l,"htmx:trigger");c(l,e)},u.delay)}else{he(l,"htmx:trigger");c(l,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:u.trigger,listener:s,on:i});i.addEventListener(u.trigger,s)})}let mt=false;let xt=null;function yt(){if(!xt){xt=function(){mt=true};window.addEventListener("scroll",xt);window.addEventListener("resize",xt);setInterval(function(){if(mt){mt=false;se(ne().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){bt(e)})}},200)}}function bt(e){if(!s(e,"data-hx-revealed")&&X(e)){e.setAttribute("data-hx-revealed","true");const t=ie(e);if(t.initHash){he(e,"revealed")}else{e.addEventListener("htmx:afterProcessNode",function(){he(e,"revealed")},{once:true})}}}function vt(e,t,n,r){const o=function(){if(!n.loaded){n.loaded=true;he(e,"htmx:trigger");t(e)}};if(r>0){E().setTimeout(o,r)}else{o()}}function wt(t,n,e){let i=false;se(r,function(r){if(s(t,"hx-"+r)){const o=te(t,"hx-"+r);i=true;n.path=o;n.verb=r;e.forEach(function(e){St(t,e,n,function(e,t){const n=ue(e);if(g(n,Q.config.disableSelector)){b(n);return}de(r,o,n,t)})})}});return i}function St(r,e,t,n){if(e.trigger==="revealed"){yt();pt(r,n,t,e);bt(ue(r))}else if(e.trigger==="intersect"){const o={};if(e.root){o.root=ae(r,e.root)}if(e.threshold){o.threshold=parseFloat(e.threshold)}const i=new IntersectionObserver(function(t){for(let e=0;e0){t.polling=true;ct(ue(r),n,e)}else{pt(r,n,t,e)}}function Et(e){const t=ue(e);if(!t){return false}const n=t.attributes;for(let e=0;e", "+e).join(""));return o}else{return[]}}function Tt(e){const t=g(ue(e.target),"button, input[type='submit']");const n=Lt(e);if(n){n.lastButtonClicked=t}}function qt(e){const t=Lt(e);if(t){t.lastButtonClicked=null}}function Lt(e){const t=g(ue(e.target),"button, input[type='submit']");if(!t){return}const n=y("#"+ee(t,"form"),t.getRootNode())||g(t,"form");if(!n){return}return ie(n)}function At(e){e.addEventListener("click",Tt);e.addEventListener("focusin",Tt);e.addEventListener("focusout",qt)}function Nt(t,e,n){const r=ie(t);if(!Array.isArray(r.onHandlers)){r.onHandlers=[]}let o;const i=function(e){vn(t,function(){if(at(t)){return}if(!o){o=new Function("event",n)}o.call(t,e)})};t.addEventListener(e,i);r.onHandlers.push({event:e,listener:i})}function It(t){ke(t);for(let e=0;eQ.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){fe(ne().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Vt(t){if(!B()){return null}t=U(t);const n=S(localStorage.getItem("htmx-history-cache"))||[];for(let e=0;e=200&&this.status<400){he(ne().body,"htmx:historyCacheMissLoad",i);const e=P(this.response);const t=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;const n=Ut();const r=xn(n);kn(e.title);qe(e);Ve(n,t,r);Te();Kt(r.tasks);Bt=o;he(ne().body,"htmx:historyRestore",{path:o,cacheMiss:true,serverResponse:this.response})}else{fe(ne().body,"htmx:historyCacheMissLoadError",i)}};e.send()}function Wt(e){zt();e=e||location.pathname+location.search;const t=Vt(e);if(t){const n=P(t.content);const r=Ut();const o=xn(r);kn(t.title);qe(n);Ve(r,n,o);Te();Kt(o.tasks);E().setTimeout(function(){window.scrollTo(0,t.scroll)},0);Bt=e;he(ne().body,"htmx:historyRestore",{path:e,item:t})}else{if(Q.config.refreshOnHistoryMiss){window.location.reload(true)}else{Gt(e)}}}function Zt(e){let t=we(e,"hx-indicator");if(t==null){t=[e]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.classList.add.call(e.classList,Q.config.requestClass)});return t}function Yt(e){let t=we(e,"hx-disabled-elt");if(t==null){t=[]}se(t,function(e){const t=ie(e);t.requestCount=(t.requestCount||0)+1;e.setAttribute("disabled","");e.setAttribute("data-disabled-by-htmx","")});return t}function Qt(e,t){se(e.concat(t),function(e){const t=ie(e);t.requestCount=(t.requestCount||1)-1});se(e,function(e){const t=ie(e);if(t.requestCount===0){e.classList.remove.call(e.classList,Q.config.requestClass)}});se(t,function(e){const t=ie(e);if(t.requestCount===0){e.removeAttribute("disabled");e.removeAttribute("data-disabled-by-htmx")}})}function en(t,n){for(let e=0;en.indexOf(e)<0)}else{e=e.filter(e=>e!==n)}r.delete(t);se(e,e=>r.append(t,e))}}function on(t,n,r,o,i){if(o==null||en(t,o)){return}else{t.push(o)}if(tn(o)){const s=ee(o,"name");let e=o.value;if(o instanceof HTMLSelectElement&&o.multiple){e=M(o.querySelectorAll("option:checked")).map(function(e){return e.value})}if(o instanceof HTMLInputElement&&o.files){e=M(o.files)}nn(s,e,n);if(i){sn(o,r)}}if(o instanceof HTMLFormElement){se(o.elements,function(e){if(t.indexOf(e)>=0){rn(e.name,e.value,n)}else{t.push(e)}if(i){sn(e,r)}});new FormData(o).forEach(function(e,t){if(e instanceof File&&e.name===""){return}nn(t,e,n)})}}function sn(e,t){const n=e;if(n.willValidate){he(n,"htmx:validation:validate");if(!n.checkValidity()){t.push({elt:n,message:n.validationMessage,validity:n.validity});he(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})}}}function ln(n,e){for(const t of e.keys()){n.delete(t)}e.forEach(function(e,t){n.append(t,e)});return n}function cn(e,t){const n=[];const r=new FormData;const o=new FormData;const i=[];const s=ie(e);if(s.lastButtonClicked&&!le(s.lastButtonClicked)){s.lastButtonClicked=null}let l=e instanceof HTMLFormElement&&e.noValidate!==true||te(e,"hx-validate")==="true";if(s.lastButtonClicked){l=l&&s.lastButtonClicked.formNoValidate!==true}if(t!=="get"){on(n,o,i,g(e,"form"),l)}on(n,r,i,e,l);if(s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&ee(e,"type")==="submit"){const u=s.lastButtonClicked||e;const a=ee(u,"name");nn(a,u.value,o)}const c=we(e,"hx-include");se(c,function(e){on(n,r,i,ue(e),l);if(!h(e,"form")){se(f(e).querySelectorAll(ot),function(e){on(n,r,i,e,l)})}});ln(r,o);return{errors:i,formData:r,values:An(r)}}function un(e,t,n){if(e!==""){e+="&"}if(String(n)==="[object Object]"){n=JSON.stringify(n)}const r=encodeURIComponent(n);e+=encodeURIComponent(t)+"="+r;return e}function an(e){e=qn(e);let n="";e.forEach(function(e,t){n=un(n,t,e)});return n}function fn(e,t,n){const r={"HX-Request":"true","HX-Trigger":ee(e,"id"),"HX-Trigger-Name":ee(e,"name"),"HX-Target":te(t,"id"),"HX-Current-URL":ne().location.href};bn(e,"hx-headers",false,r);if(n!==undefined){r["HX-Prompt"]=n}if(ie(e).boosted){r["HX-Boosted"]="true"}return r}function hn(n,e){const t=re(e,"hx-params");if(t){if(t==="none"){return new FormData}else if(t==="*"){return n}else if(t.indexOf("not ")===0){se(t.slice(4).split(","),function(e){e=e.trim();n.delete(e)});return n}else{const r=new FormData;se(t.split(","),function(t){t=t.trim();if(n.has(t)){n.getAll(t).forEach(function(e){r.append(t,e)})}});return r}}else{return n}}function dn(e){return!!ee(e,"href")&&ee(e,"href").indexOf("#")>=0}function gn(e,t){const n=t||re(e,"hx-swap");const r={swapStyle:ie(e).boosted?"innerHTML":Q.config.defaultSwapStyle,swapDelay:Q.config.defaultSwapDelay,settleDelay:Q.config.defaultSettleDelay};if(Q.config.scrollIntoViewOnBoost&&ie(e).boosted&&!dn(e)){r.show="top"}if(n){const s=F(n);if(s.length>0){for(let e=0;e0?o.join(":"):null;r.scroll=u;r.scrollTarget=i}else if(l.indexOf("show:")===0){const a=l.slice(5);var o=a.split(":");const f=o.pop();var i=o.length>0?o.join(":"):null;r.show=f;r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){const h=l.slice("focus-scroll:".length);r.focusScroll=h=="true"}else if(e==0){r.swapStyle=l}else{O("Unknown modifier in hx-swap: "+l)}}}}return r}function pn(e){return re(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&ee(e,"enctype")==="multipart/form-data"}function mn(t,n,r){let o=null;Ft(n,function(e){if(o==null){o=e.encodeParameters(t,r,n)}});if(o!=null){return o}else{if(pn(n)){return ln(new FormData,qn(r))}else{return an(r)}}}function xn(e){return{tasks:[],elts:[e]}}function yn(e,t){const n=e[0];const r=e[e.length-1];if(t.scroll){var o=null;if(t.scrollTarget){o=ue(ae(n,t.scrollTarget))}if(t.scroll==="top"&&(n||o)){o=o||n;o.scrollTop=0}if(t.scroll==="bottom"&&(r||o)){o=o||r;o.scrollTop=o.scrollHeight}}if(t.show){var o=null;if(t.showTarget){let e=t.showTarget;if(t.showTarget==="window"){e="body"}o=ue(ae(n,e))}if(t.show==="top"&&(n||o)){o=o||n;o.scrollIntoView({block:"start",behavior:Q.config.scrollBehavior})}if(t.show==="bottom"&&(r||o)){o=o||r;o.scrollIntoView({block:"end",behavior:Q.config.scrollBehavior})}}}function bn(r,e,o,i){if(i==null){i={}}if(r==null){return i}const s=te(r,e);if(s){let e=s.trim();let t=o;if(e==="unset"){return null}if(e.indexOf("javascript:")===0){e=e.slice(11);t=true}else if(e.indexOf("js:")===0){e=e.slice(3);t=true}if(e.indexOf("{")!==0){e="{"+e+"}"}let n;if(t){n=vn(r,function(){return Function("return ("+e+")")()},{})}else{n=S(e)}for(const l in n){if(n.hasOwnProperty(l)){if(i[l]==null){i[l]=n[l]}}}}return bn(ue(c(r)),e,o,i)}function vn(e,t,n){if(Q.config.allowEval){return t()}else{fe(e,"htmx:evalDisallowedError");return n}}function wn(e,t){return bn(e,"hx-vars",true,t)}function Sn(e,t){return bn(e,"hx-vals",false,t)}function En(e){return ce(wn(e),Sn(e))}function Cn(t,n,r){if(r!==null){try{t.setRequestHeader(n,r)}catch(e){t.setRequestHeader(n,encodeURIComponent(r));t.setRequestHeader(n+"-URI-AutoEncoded","true")}}}function On(t){if(t.responseURL&&typeof URL!=="undefined"){try{const e=new URL(t.responseURL);return e.pathname+e.search}catch(e){fe(ne().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function R(e,t){return t.test(e.getAllResponseHeaders())}function Rn(t,n,r){t=t.toLowerCase();if(r){if(r instanceof Element||typeof r==="string"){return de(t,n,null,null,{targetOverride:y(r)||ve,returnPromise:true})}else{let e=y(r.target);if(r.target&&!e||r.source&&!e&&!y(r.source)){e=ve}return de(t,n,y(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:e,swapOverride:r.swap,select:r.select,returnPromise:true})}}else{return de(t,n,null,null,{returnPromise:true})}}function Hn(e){const t=[];while(e){t.push(e);e=e.parentElement}return t}function Tn(e,t,n){let r;let o;if(typeof URL==="function"){o=new URL(t,document.location.href);const i=document.location.origin;r=i===o.origin}else{o=t;r=l(t,document.location.origin)}if(Q.config.selfRequestsOnly){if(!r){return false}}return he(e,"htmx:validateUrl",ce({url:o,sameHost:r},n))}function qn(e){if(e instanceof FormData)return e;const t=new FormData;for(const n in e){if(e.hasOwnProperty(n)){if(e[n]&&typeof e[n].forEach==="function"){e[n].forEach(function(e){t.append(n,e)})}else if(typeof e[n]==="object"&&!(e[n]instanceof Blob)){t.append(n,JSON.stringify(e[n]))}else{t.append(n,e[n])}}}return t}function Ln(r,o,e){return new Proxy(e,{get:function(t,e){if(typeof e==="number")return t[e];if(e==="length")return t.length;if(e==="push"){return function(e){t.push(e);r.append(o,e)}}if(typeof t[e]==="function"){return function(){t[e].apply(t,arguments);r.delete(o);t.forEach(function(e){r.append(o,e)})}}if(t[e]&&t[e].length===1){return t[e][0]}else{return t[e]}},set:function(e,t,n){e[t]=n;r.delete(o);e.forEach(function(e){r.append(o,e)});return true}})}function An(o){return new Proxy(o,{get:function(e,t){if(typeof t==="symbol"){const r=Reflect.get(e,t);if(typeof r==="function"){return function(){return r.apply(o,arguments)}}else{return r}}if(t==="toJSON"){return()=>Object.fromEntries(o)}if(t in e){if(typeof e[t]==="function"){return function(){return o[t].apply(o,arguments)}}else{return e[t]}}const n=o.getAll(t);if(n.length===0){return undefined}else if(n.length===1){return n[0]}else{return Ln(e,t,n)}},set:function(t,n,e){if(typeof n!=="string"){return false}t.delete(n);if(e&&typeof e.forEach==="function"){e.forEach(function(e){t.append(n,e)})}else if(typeof e==="object"&&!(e instanceof Blob)){t.append(n,JSON.stringify(e))}else{t.append(n,e)}return true},deleteProperty:function(e,t){if(typeof t==="string"){e.delete(t)}return true},ownKeys:function(e){return Reflect.ownKeys(Object.fromEntries(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(e),t)}})}function de(t,n,r,o,i,D){let s=null;let l=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var e=new Promise(function(e,t){s=e;l=t})}if(r==null){r=ne().body}const M=i.handler||Dn;const X=i.select||null;if(!le(r)){oe(s);return e}const c=i.targetOverride||ue(Ee(r));if(c==null||c==ve){fe(r,"htmx:targetError",{target:te(r,"hx-target")});oe(l);return e}let u=ie(r);const a=u.lastButtonClicked;if(a){const L=ee(a,"formaction");if(L!=null){n=L}const A=ee(a,"formmethod");if(A!=null){if(A.toLowerCase()!=="dialog"){t=A}}}const f=re(r,"hx-confirm");if(D===undefined){const K=function(e){return de(t,n,r,o,i,!!e)};const G={target:c,elt:r,path:n,verb:t,triggeringEvent:o,etc:i,issueRequest:K,question:f};if(he(r,"htmx:confirm",G)===false){oe(s);return e}}let h=r;let d=re(r,"hx-sync");let g=null;let F=false;if(d){const N=d.split(":");const I=N[0].trim();if(I==="this"){h=Se(r,"hx-sync")}else{h=ue(ae(r,I))}d=(N[1]||"drop").trim();u=ie(h);if(d==="drop"&&u.xhr&&u.abortable!==true){oe(s);return e}else if(d==="abort"){if(u.xhr){oe(s);return e}else{F=true}}else if(d==="replace"){he(h,"htmx:abort")}else if(d.indexOf("queue")===0){const W=d.split(" ");g=(W[1]||"last").trim()}}if(u.xhr){if(u.abortable){he(h,"htmx:abort")}else{if(g==null){if(o){const P=ie(o);if(P&&P.triggerSpec&&P.triggerSpec.queue){g=P.triggerSpec.queue}}if(g==null){g="last"}}if(u.queuedRequests==null){u.queuedRequests=[]}if(g==="first"&&u.queuedRequests.length===0){u.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="all"){u.queuedRequests.push(function(){de(t,n,r,o,i)})}else if(g==="last"){u.queuedRequests=[];u.queuedRequests.push(function(){de(t,n,r,o,i)})}oe(s);return e}}const p=new XMLHttpRequest;u.xhr=p;u.abortable=F;const m=function(){u.xhr=null;u.abortable=false;if(u.queuedRequests!=null&&u.queuedRequests.length>0){const e=u.queuedRequests.shift();e()}};const B=re(r,"hx-prompt");if(B){var x=prompt(B);if(x===null||!he(r,"htmx:prompt",{prompt:x,target:c})){oe(s);m();return e}}if(f&&!D){if(!confirm(f)){oe(s);m();return e}}let y=fn(r,c,x);if(t!=="get"&&!pn(r)){y["Content-Type"]="application/x-www-form-urlencoded"}if(i.headers){y=ce(y,i.headers)}const U=cn(r,t);let b=U.errors;const j=U.formData;if(i.values){ln(j,qn(i.values))}const V=qn(En(r));const v=ln(j,V);let w=hn(v,r);if(Q.config.getCacheBusterParam&&t==="get"){w.set("org.htmx.cache-buster",ee(c,"id")||"true")}if(n==null||n===""){n=ne().location.href}const S=bn(r,"hx-request");const _=ie(r).boosted;let E=Q.config.methodsThatUseUrlParams.indexOf(t)>=0;const C={boosted:_,useUrlParams:E,formData:w,parameters:An(w),unfilteredFormData:v,unfilteredParameters:An(v),headers:y,target:c,verb:t,errors:b,withCredentials:i.credentials||S.credentials||Q.config.withCredentials,timeout:i.timeout||S.timeout||Q.config.timeout,path:n,triggeringEvent:o};if(!he(r,"htmx:configRequest",C)){oe(s);m();return e}n=C.path;t=C.verb;y=C.headers;w=qn(C.parameters);b=C.errors;E=C.useUrlParams;if(b&&b.length>0){he(r,"htmx:validation:halted",C);oe(s);m();return e}const z=n.split("#");const $=z[0];const O=z[1];let R=n;if(E){R=$;const Z=!w.keys().next().done;if(Z){if(R.indexOf("?")<0){R+="?"}else{R+="&"}R+=an(w);if(O){R+="#"+O}}}if(!Tn(r,R,C)){fe(r,"htmx:invalidPath",C);oe(l);return e}p.open(t.toUpperCase(),R,true);p.overrideMimeType("text/html");p.withCredentials=C.withCredentials;p.timeout=C.timeout;if(S.noHeaders){}else{for(const k in y){if(y.hasOwnProperty(k)){const Y=y[k];Cn(p,k,Y)}}}const H={xhr:p,target:c,requestConfig:C,etc:i,boosted:_,select:X,pathInfo:{requestPath:n,finalRequestPath:R,responsePath:null,anchor:O}};p.onload=function(){try{const t=Hn(r);H.pathInfo.responsePath=On(p);M(r,H);if(H.keepIndicators!==true){Qt(T,q)}he(r,"htmx:afterRequest",H);he(r,"htmx:afterOnLoad",H);if(!le(r)){let e=null;while(t.length>0&&e==null){const n=t.shift();if(le(n)){e=n}}if(e){he(e,"htmx:afterRequest",H);he(e,"htmx:afterOnLoad",H)}}oe(s);m()}catch(e){fe(r,"htmx:onLoadError",ce({error:e},H));throw e}};p.onerror=function(){Qt(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:sendError",H);oe(l);m()};p.onabort=function(){Qt(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:sendAbort",H);oe(l);m()};p.ontimeout=function(){Qt(T,q);fe(r,"htmx:afterRequest",H);fe(r,"htmx:timeout",H);oe(l);m()};if(!he(r,"htmx:beforeRequest",H)){oe(s);m();return e}var T=Zt(r);var q=Yt(r);se(["loadstart","loadend","progress","abort"],function(t){se([p,p.upload],function(e){e.addEventListener(t,function(e){he(r,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});he(r,"htmx:beforeSend",H);const J=E?null:mn(p,r,w);p.send(J);return e}function Nn(e,t){const n=t.xhr;let r=null;let o=null;if(R(n,/HX-Push:/i)){r=n.getResponseHeader("HX-Push");o="push"}else if(R(n,/HX-Push-Url:/i)){r=n.getResponseHeader("HX-Push-Url");o="push"}else if(R(n,/HX-Replace-Url:/i)){r=n.getResponseHeader("HX-Replace-Url");o="replace"}if(r){if(r==="false"){return{}}else{return{type:o,path:r}}}const i=t.pathInfo.finalRequestPath;const s=t.pathInfo.responsePath;const l=re(e,"hx-push-url");const c=re(e,"hx-replace-url");const u=ie(e).boosted;let a=null;let f=null;if(l){a="push";f=l}else if(c){a="replace";f=c}else if(u){a="push";f=s||i}if(f){if(f==="false"){return{}}if(f==="true"){f=s||i}if(t.pathInfo.anchor&&f.indexOf("#")===-1){f=f+"#"+t.pathInfo.anchor}return{type:a,path:f}}else{return{}}}function In(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function Pn(e){for(var t=0;t0){E().setTimeout(e,x.swapDelay)}else{e()}}if(f){fe(o,"htmx:responseError",ce({error:"Response Status Error Code "+s.status+" from "+i.pathInfo.requestPath},i))}}const Mn={};function Xn(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,n,r){return false},encodeParameters:function(e,t,n){return null}}}function Fn(e,t){if(t.init){t.init(n)}Mn[e]=ce(Xn(),t)}function Bn(e){delete Mn[e]}function Un(e,n,r){if(n==undefined){n=[]}if(e==undefined){return n}if(r==undefined){r=[]}const t=te(e,"hx-ext");if(t){se(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){r.push(e.slice(7));return}if(r.indexOf(e)<0){const t=Mn[e];if(t&&n.indexOf(t)<0){n.push(t)}}})}return Un(ue(c(e)),n,r)}var jn=false;ne().addEventListener("DOMContentLoaded",function(){jn=true});function Vn(e){if(jn||ne().readyState==="complete"){e()}else{ne().addEventListener("DOMContentLoaded",e)}}function _n(){if(Q.config.includeIndicatorStyles!==false){const e=Q.config.inlineStyleNonce?` nonce="${Q.config.inlineStyleNonce}"`:"";ne().head.insertAdjacentHTML("beforeend"," ."+Q.config.indicatorClass+"{opacity:0} ."+Q.config.requestClass+" ."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ."+Q.config.requestClass+"."+Q.config.indicatorClass+"{opacity:1; transition: opacity 200ms ease-in;} ")}}function zn(){const e=ne().querySelector('meta[name="htmx-config"]');if(e){return S(e.content)}else{return null}}function $n(){const e=zn();if(e){Q.config=ce(Q.config,e)}}Vn(function(){$n();_n();let e=ne().body;kt(e);const t=ne().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){const t=e.target;const n=ie(t);if(n&&n.xhr){n.xhr.abort()}});const n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(e){if(e.state&&e.state.htmx){Wt();se(t,function(e){he(e,"htmx:restored",{document:ne(),triggerEvent:he})})}else{if(n){n(e)}}};E().setTimeout(function(){he(e,"htmx:load",{});e=null},0)});return Q}(); \ No newline at end of file diff --git a/assets/js/utils.js b/assets/js/utils.js new file mode 100644 index 0000000..901393e --- /dev/null +++ b/assets/js/utils.js @@ -0,0 +1,39 @@ +var DecimalPrecision = (function() { + if (Math.trunc === undefined) { + Math.trunc = function(v) { + return v < 0 ? Math.ceil(v) : Math.floor(v); + }; + } + var decimalAdjust = function myself(type, num, decimalPlaces) { + if (type === 'round' && num < 0) + return -myself(type, -num, decimalPlaces); + var shift = function(value, exponent) { + value = (value + 'e').split('e'); + return +(value[0] + 'e' + (+value[1] + (exponent || 0))); + }; + var n = shift(num, +decimalPlaces); + return shift(Math[type](n), -decimalPlaces); + }; + return { + // Decimal round (half away from zero) + round: function(num, decimalPlaces) { + return decimalAdjust('round', num, decimalPlaces); + }, + // Decimal ceil + ceil: function(num, decimalPlaces) { + return decimalAdjust('ceil', num, decimalPlaces); + }, + // Decimal floor + floor: function(num, decimalPlaces) { + return decimalAdjust('floor', num, decimalPlaces); + }, + // Decimal trunc + trunc: function(num, decimalPlaces) { + return decimalAdjust('trunc', num, decimalPlaces); + }, + // Format using fixed-point notation + toFixed: function(num, decimalPlaces) { + return decimalAdjust('round', num, decimalPlaces).toFixed(decimalPlaces); + } + }; +})(); diff --git a/assets/learnlytics.png b/assets/learnlytics.png new file mode 100644 index 0000000..9281f10 Binary files /dev/null and b/assets/learnlytics.png differ diff --git a/components/charts.templ b/components/charts.templ new file mode 100644 index 0000000..4076cc7 --- /dev/null +++ b/components/charts.templ @@ -0,0 +1,82 @@ +package components + +templ barChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) { +
+ + @templ.JSFuncCall( + "barChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ) +
+} + +templ barLineChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) { +
+ +
+ @templ.JSFuncCall( + "barLineChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ) +
+} + +templ pieChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) { +
+ + @templ.JSFuncCall( + "pieChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ) +
+} + +templ doughnutChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) { +
+ + @templ.JSFuncCall( + "doughnutChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ) +
+} + +templ polarChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) { +
+ + @templ.JSFuncCall( + "polarChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ) +
+} diff --git a/components/charts_templ.go b/components/charts_templ.go new file mode 100644 index 0000000..af54ab3 --- /dev/null +++ b/components/charts_templ.go @@ -0,0 +1,306 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func barChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall( + "barChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func barLineChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall( + "barLineChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func pieChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall( + "pieChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func doughnutChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall( + "doughnutChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func polarChart(id string, data []float64, labels []string, tooltip string, title string, scaleLabelX string, scaleLabelY string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall( + "polarChart", + id, + data, + labels, + tooltip, + title, + scaleLabelX, + scaleLabelY, + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/components/components.templ b/components/components.templ new file mode 100644 index 0000000..cbfac29 --- /dev/null +++ b/components/components.templ @@ -0,0 +1,240 @@ +package components + +import ( + "time" + "strconv" + "math/rand/v2" +) + +func getCurrentTime() string { + loc, err := time.LoadLocation("Europe/Berlin") + + if err != nil { + + } + + t := time.Now().In(loc) + layout := "02.01.2006 15:04" + return t.Format(layout) +} + +func genRandomData(count int) []float64 { + data := make([]float64, count) + for i := 0; i < count; i++ { + data[i] = rand.NormFloat64() * 30 + 50 + } + return data +} + +templ base(title string) { + + + + + + + + + + + + + + + + + + + Learnlytics - { title } + + + + + + + + + @navbar() +
+ { children... } +
+ + +} + +templ footer() { +
+

Author: @DerGrumpf

+
+} + +templ navbar() { + +} + +templ selectList(labels []string) { +
+
+
+ Students: + for index, label := range labels { + +

+ } +
+
+
+} + +templ usercard(username string) { +
+ Avatar +

{ username }

+
+
+

Insitution:

+
+
+

IFN @ TU BS

+
+ +
+

Mail:

+
+
+

p.keier@beyerstedt-it.de

+
+ +
+

Created:

+
+
+

{ getCurrentTime() }

+
+
+
+} + +templ NotFound() { + @base("Error") { +
+

404 - Not Found

+
+ Dead Smiley + Failed Exam +
+

This Page Didn't Pass the Exam

+

It tried, but it didn’t make the cut.

+

Better check the Dashboard instead!

+
+ } +} + +templ Test() { + @base("Test") { +
+
+ Test +
+
+ @polarChart( + "1", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ) +
+
+ Test +
+
+ @doughnutChart( + "1", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ) +
+
+ } +} + +templ Dashboard(username string) { + @base("Dashboard") { +
+
+ @usercard(username) +
+
+ @barChart( + "2", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ) +
+ +
+ @selectList([]string{"Phil Keier", "Calvin Brandt", "Nova Eib"}) +
+ +
+ @barLineChart( + "1", + []float64{31, 15, 18, 35, 20, 20, 22, 27, 24, 30}, + []string{"Tutorial 1", "Tutorial 2", "Extended Applications", "Numpy & MatPlotLib", "SciPy", "MonteCarlo", "Pandas & Seaborn", "Folium", "Statistical Test Methods", "Data Analysis"}, + "Points scored", + "Lectures", + "Lectures", + "Points", + ) +
+
+ } +} + +templ Login() { + @base("Login") { + + } +} diff --git a/components/components_templ.go b/components/components_templ.go new file mode 100644 index 0000000..64e04ff --- /dev/null +++ b/components/components_templ.go @@ -0,0 +1,554 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "math/rand/v2" + "strconv" + "time" +) + +func getCurrentTime() string { + loc, err := time.LoadLocation("Europe/Berlin") + + if err != nil { + + } + + t := time.Now().In(loc) + layout := "02.01.2006 15:04" + return t.Format(layout) +} + +func genRandomData(count int) []float64 { + data := make([]float64, count) + for i := 0; i < count; i++ { + data[i] = rand.NormFloat64()*30 + 50 + } + return data +} + +func base(title string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Learnlytics - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/components.templ`, Line: 51, Col: 40} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = navbar().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func footer() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

Author: @DerGrumpf

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func navbar() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func selectList(labels []string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
Students: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for index, label := range labels { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func usercard(username string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
\"Avatar\"

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(username) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/components.templ`, Line: 113, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "

Insitution:

IFN @ TU BS

Mail:

p.keier@beyerstedt-it.de

Created:

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(getCurrentTime()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/components.templ`, Line: 133, Col: 37} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func NotFound() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var12 := templ.GetChildren(ctx) + if templ_7745c5c3_Var12 == nil { + templ_7745c5c3_Var12 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var13 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

404 - Not Found

\"Dead \"Failed

This Page Didn't Pass the Exam

It tried, but it didn’t make the cut.

Better check the Dashboard instead!

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base("Error").Render(templ.WithChildren(ctx, templ_7745c5c3_Var13), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Test() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var14 := templ.GetChildren(ctx) + if templ_7745c5c3_Var14 == nil { + templ_7745c5c3_Var14 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var15 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
Test
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = polarChart( + "1", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
Test
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = doughnutChart( + "1", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base("Test").Render(templ.WithChildren(ctx, templ_7745c5c3_Var15), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Dashboard(username string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var17 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = usercard(username).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = barChart( + "2", + genRandomData(6), + []string{"Klasse 8a", "Klasse 5b", "Klasse 6c", "Klasse 10d", "Englisch LK 12", "Geschickte GK 11"}, + "Points scored", + "Classes", + "Classes", + "", + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = selectList([]string{"Phil Keier", "Calvin Brandt", "Nova Eib"}).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = barLineChart( + "1", + []float64{31, 15, 18, 35, 20, 20, 22, 27, 24, 30}, + []string{"Tutorial 1", "Tutorial 2", "Extended Applications", "Numpy & MatPlotLib", "SciPy", "MonteCarlo", "Pandas & Seaborn", "Folium", "Statistical Test Methods", "Data Analysis"}, + "Points scored", + "Lectures", + "Lectures", + "Points", + ).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base("Dashboard").Render(templ.WithChildren(ctx, templ_7745c5c3_Var17), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Login() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var18 := templ.GetChildren(ctx) + if templ_7745c5c3_Var18 == nil { + templ_7745c5c3_Var18 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var19 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
\"Learnlytics

Learnlytics





") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = base("Login").Render(templ.WithChildren(ctx, templ_7745c5c3_Var19), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/components/go.mod b/components/go.mod new file mode 100644 index 0000000..1b619b0 --- /dev/null +++ b/components/go.mod @@ -0,0 +1,5 @@ +module components + +go 1.24.1 + +require github.com/a-h/templ v0.3.833 diff --git a/components/go.sum b/components/go.sum new file mode 100644 index 0000000..bbe292f --- /dev/null +++ b/components/go.sum @@ -0,0 +1,4 @@ +github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU= +github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/db/go.mod b/db/go.mod new file mode 100644 index 0000000..f75d104 --- /dev/null +++ b/db/go.mod @@ -0,0 +1,20 @@ +module db + +go 1.24.1 + +require ( + gorm.io/driver/postgres v1.5.11 + gorm.io/gorm v1.25.12 +) + +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.2 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/text v0.23.0 // indirect +) diff --git a/db/go.sum b/db/go.sum new file mode 100644 index 0000000..3a8514c --- /dev/null +++ b/db/go.sum @@ -0,0 +1,36 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/db/model.go b/db/model.go new file mode 100644 index 0000000..709c2fa --- /dev/null +++ b/db/model.go @@ -0,0 +1,78 @@ +package db + +import ( + "gorm.io/driver/postgres" + "gorm.io/gorm" + "fmt" + "time" +) + +type Class struct { + id uint "gorm:primaryKey" + name string + created_at time.Time +} + +type Student struct { + id uint "gorm:primaryKey" + prename string + surname string + sex string + study_id uint + class_id uint + group_id uint + created_at time.Time +} + +type Study struct { + id uint "gorm:primaryKey" + name string + created_at time.Time +} + +type Lecture struct { + id uint "gorm:primaryKey" + title string + points uint + class_id uint + created_at time.Time +} + +type Submission struct { + id uint "gorm:primaryKey" + student_id uint + lecture_id uint + class_id uint + points float32 + created_at time.Time +} + +type Group struct { + id uint "gorm:primaryKey" + name string + project string + has_passed bool + presentation string + class_id uint + created_at time.Time +} + +func ConnectDB() *gorm.DB { + dsn := "host=postgres.cyperpunk.de user=dergrumpf password=1P2h3i4lon$% dbname=phil port=5432 sslmode=disable TimeZone=Europe/Berlin" + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + + if err != nil { + fmt.Println(err) + } + + db.AutoMigrate( + &Class{}, + &Student{}, + &Study{}, + &Lecture{}, + &Submission{}, + &Group{}, + ) + + return db +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..861e5da --- /dev/null +++ b/go.mod @@ -0,0 +1,32 @@ +module learnlytics-go + +go 1.24.1 + +require ( + components v0.0.0-00010101000000-000000000000 + github.com/a-h/templ v0.3.833 +) + +require ( + db v0.0.0-00010101000000-000000000000 // indirect + github.com/alexedwards/scs/v2 v2.8.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.2 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/text v0.23.0 // indirect + gorm.io/driver/postgres v1.5.11 // indirect + gorm.io/gorm v1.25.12 // indirect +) + +replace github.com/a-h/templ => ./templ + +replace components => ./components + +replace db => ./db + +replace handlers => ./handlers diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1febbf6 --- /dev/null +++ b/go.sum @@ -0,0 +1,33 @@ +github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= +github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= diff --git a/handlers/go.mod b/handlers/go.mod new file mode 100644 index 0000000..5df149a --- /dev/null +++ b/handlers/go.mod @@ -0,0 +1,3 @@ +module handlers + +go 1.24.1 diff --git a/handlers/handler.go b/handlers/handler.go new file mode 100644 index 0000000..4d943f2 --- /dev/null +++ b/handlers/handler.go @@ -0,0 +1,11 @@ +package handlers + +import "gorm.io/gorm" + +type handler struct { + DB *gorm.DB +} + +func New(db *gorm.DB) handler { + return handler{db} +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..3758828 --- /dev/null +++ b/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "net/http" + "time" + "components" + //"db" + "github.com/a-h/templ" + "github.com/alexedwards/scs/v2" +) + +var sessionManager *scs.SessionManager + +func getHandler(w http.ResponseWriter, r *http.Request) { + component := components.Dashboard("DerGrumpf") + component.Render(r.Context(), w) +} + +func postHandler(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + + username := r.Form["username"][0] + component := components.Dashboard(username) + component.Render(r.Context(), w) +} + +func errorHandler(w http.ResponseWriter, r *http.Request, status int) { + w.WriteHeader(status) + if status == http.StatusNotFound { + component := components.NotFound() + component.Render(r.Context(), w) + } +} + +func testHandler(w http.ResponseWriter, r *http.Request) { + component := components.Test() + component.Render(r.Context(), w) +} + +func initMux() *http.ServeMux { + + mux := http.NewServeMux() + + // Index Handle + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + errorHandler(w, r, http.StatusNotFound) + return + } + + if r.Method == http.MethodPost { + postHandler(w, r) + return + } + getHandler(w, r) + }) + + // File Server + mux.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets")))) + + mux.HandleFunc("/test", testHandler) + + return mux +} + + +func main() { + sessionManager := scs.New() + sessionManager.Lifetime = 24 * time.Hour + sessionManager.Cookie.Persist = false + + mux := initMux() + + component := components.Login() + http.Handle("/", templ.Handler(component)) + + fmt.Println("Listening on http://127.0.0.1:3000") + if err := http.ListenAndServe(":3000", sessionManager.LoadAndSave(mux)); err != nil { + fmt.Println("Error listening: %v", err) + } +} diff --git a/templ/.dockerignore b/templ/.dockerignore new file mode 100644 index 0000000..17896fe --- /dev/null +++ b/templ/.dockerignore @@ -0,0 +1,3 @@ +.git +Dockerfile +.dockerignore diff --git a/templ/.envrc b/templ/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/templ/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/templ/.github/FUNDING.yml b/templ/.github/FUNDING.yml new file mode 100644 index 0000000..22f305d --- /dev/null +++ b/templ/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [a-h, joerdav] diff --git a/templ/.github/ISSUE_TEMPLATE/bug_report.md b/templ/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..cf03af0 --- /dev/null +++ b/templ/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Before you begin** +Please make sure you're using the latest version of the templ CLI (`go install github.com/a-h/templ/cmd/templ@latest`), and have upgraded your project to use the latest version of the templ runtime (`go get -u github.com/a-h/templ@latest`) + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +A small, self-container, complete reproduction, uploaded to a GitHub repo, containing the minimum amount of files required to reproduce the behaviour, along with a list of commands that need to be run. Keep it simple. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots or screen captures to help explain your problem. + +**Logs** +If the issue is related to IDE support, run through the LSP troubleshooting section at https://templ.guide/commands-and-tools/ide-support/#troubleshooting-1 and include logs from templ + +**`templ info` output** +Run `templ info` and include the output. + +**Desktop (please complete the following information):** + - OS: [e.g. MacOS, Linux, Windows, WSL] + - templ CLI version (`templ version`) +- Go version (`go version`) +- `gopls` version (`gopls version`) + +**Additional context** +Add any other context about the problem here. diff --git a/templ/.github/workflows/ci.yml b/templ/.github/workflows/ci.yml new file mode 100644 index 0000000..56722a4 --- /dev/null +++ b/templ/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DeterminateSystems/nix-installer-action@v16 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: DeterminateSystems/magic-nix-cache-action@v8 + + - name: Test + run: nix develop --command xc test-cover + + - name: Copy coverage.out to temp + run: cp coverage.out $RUNNER_TEMP + + - name: Update coverage report + uses: ncruces/go-coverage-report@57ac6f0f19874f7afbab596105154f08004f482e + with: + coverage-file: ${{ runner.temp }}/coverage.out + report: 'true' + chart: 'true' + reuse-go: 'true' + if: | + github.event_name == 'push' + + - name: Build + run: nix build + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DeterminateSystems/nix-installer-action@v16 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: DeterminateSystems/magic-nix-cache-action@v8 + + - name: Lint + run: nix develop --command xc lint + + ensure-generated: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DeterminateSystems/nix-installer-action@v16 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: DeterminateSystems/magic-nix-cache-action@v8 + + - name: Generate + run: nix develop --command xc ensure-generated + + ensure-fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: DeterminateSystems/nix-installer-action@v16 + with: + github_access_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: DeterminateSystems/magic-nix-cache-action@v8 + + - name: Fmt + run: nix develop --command xc fmt + + - name: Ensure clean + run: git diff --exit-code diff --git a/templ/.github/workflows/docs.yaml b/templ/.github/workflows/docs.yaml new file mode 100644 index 0000000..2dff2bc --- /dev/null +++ b/templ/.github/workflows/docs.yaml @@ -0,0 +1,60 @@ +name: Deploy Docs + +on: + release: + types: [published] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +defaults: + run: + shell: bash + +jobs: + build-docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: "./docs/package-lock.json" + - name: Install Node.js dependencies + run: | + cd docs + npm ci + - name: Build + run: | + cd docs + npm run build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./docs/build + + deploy-docs: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build-docs + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/templ/.github/workflows/release.yml b/templ/.github/workflows/release.yml new file mode 100644 index 0000000..c19a3ab --- /dev/null +++ b/templ/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +permissions: + contents: write + packages: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version: 1.22 + cache: true + - uses: ko-build/setup-ko@v0.7 + - uses: sigstore/cosign-installer@v3.7.0 + with: + cosign-release: v2.2.3 + - uses: goreleaser/goreleaser-action@v5 + with: + version: v1.24.0 + args: release --clean + env: + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + COSIGN_PASSWORD: '${{ secrets.COSIGN_PASSWORD }}' + COSIGN_PRIVATE_KEY: '${{ secrets.COSIGN_PRIVATE_KEY }}' + COSIGN_PUBLIC_KEY: '${{ secrets.COSIGN_PUBLIC_KEY }}' diff --git a/templ/.gitignore b/templ/.gitignore new file mode 100644 index 0000000..0420c67 --- /dev/null +++ b/templ/.gitignore @@ -0,0 +1,34 @@ +# Output. +cmd/templ/templ + +# Logs. +cmd/templ/lspcmd/*log.txt + +# Go code coverage. +coverage.out +coverage + +# Mac filesystem jank. +.DS_Store + +# Docusaurus. +docs/build/ +docs/resources/_gen/ +node_modules/ +dist/ + +# Nix artifacts. +result + +# Editors +## nvim +.null-ls* + +# Go workspace. +go.work + +# direnv +.direnv + +# templ txt files. +*_templ.txt diff --git a/templ/.goreleaser.yaml b/templ/.goreleaser.yaml new file mode 100644 index 0000000..456187c --- /dev/null +++ b/templ/.goreleaser.yaml @@ -0,0 +1,72 @@ +builds: + - env: + - CGO_ENABLED=0 + dir: cmd/templ + mod_timestamp: '{{ .CommitTimestamp }}' + flags: + - -trimpath + ldflags: + - -s -w + goos: + - linux + - windows + - darwin + +checksum: + name_template: 'checksums.txt' + +signs: + - id: checksums + cmd: cosign + stdin: '{{ .Env.COSIGN_PASSWORD }}' + output: true + artifacts: checksum + args: + - sign-blob + - --yes + - --key + - env://COSIGN_PRIVATE_KEY + - '--output-certificate=${certificate}' + - '--output-signature=${signature}' + - '${artifact}' + +archives: + - format: tar.gz + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + +kos: + - repository: ghcr.io/a-h/templ + platforms: + - linux/amd64 + - linux/arm64 + tags: + - latest + - '{{.Tag}}' + bare: true + +docker_signs: + - cmd: cosign + artifacts: all + output: true + args: + - sign + - --yes + - --key + - env://COSIGN_PRIVATE_KEY + - '${artifact}' + +snapshot: + name_template: "{{ incpatch .Version }}-next" + +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/templ/.ignore b/templ/.ignore new file mode 100644 index 0000000..9377535 --- /dev/null +++ b/templ/.ignore @@ -0,0 +1,9 @@ +*_templ.go +examples/integration-ct/static/index.js +examples/counter/assets/css/bulma.* +examples/counter/assets/js/htmx.min.js +examples/counter-basic/assets/css/bulma.* +examples/typescript/assets/index.js +package-lock.json +go.sum +docs/static/llms.md diff --git a/templ/.version b/templ/.version new file mode 100644 index 0000000..46a3c4a --- /dev/null +++ b/templ/.version @@ -0,0 +1 @@ +0.3.833 \ No newline at end of file diff --git a/templ/.vscode/settings.json b/templ/.vscode/settings.json new file mode 100644 index 0000000..7ccb52a --- /dev/null +++ b/templ/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "cSpell.words": [ + "blockquote", + "fieldset", + "figcaption", + "formatstring", + "goexpression", + "keygen", + "strs", + "templ" + ] +} \ No newline at end of file diff --git a/templ/CODE_OF_CONDUCT.md b/templ/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..08340d3 --- /dev/null +++ b/templ/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +adrianhesketh@hushail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/templ/CONTRIBUTING.md b/templ/CONTRIBUTING.md new file mode 100644 index 0000000..e98d31f --- /dev/null +++ b/templ/CONTRIBUTING.md @@ -0,0 +1,244 @@ +# Contributing to templ + +## Vision + +Enable Go developers to build strongly typed, component-based HTML user interfaces with first-class developer tooling, and a short learning curve. + +## Come up with a design and share it + +Before starting work on any major pull requests or code changes, start a discussion at https://github.com/a-h/templ/discussions or raise an issue. + +We don't want you to spend time on a PR or feature that ultimately doesn't get merged because it doesn't fit with the project goals, or the design doesn't work for some reason. + +For issues, it really helps if you provide a reproduction repo, or can create a failing unit test to describe the behaviour. + +In designs, we need to consider: + +* Backwards compatibility - Not changing the public API between releases, introducing gradual deprecation - don't break people's code. +* Correctness over time - How can we reduce the risk of defects both now, and in future releases? +* Threat model - How could each change be used to inject vulnerabilities into web pages? +* Go version - We target the oldest supported version of Go as per https://go.dev/doc/devel/release +* Automatic migration - If we need to force through a change. +* Compile time vs runtime errors - Prefer compile time. +* Documentation - New features are only useful if people can understand the new feature, what would the documentation look like? +* Examples - How will we demonstrate the feature? + +## Project structure + +templ is structured into a few areas: + +### Parser `./parser` + +The parser directory currently contains both v1 and v2 parsers. + +The v1 parser is not maintained, it's only used to migrate v1 code over to the v2 syntax. + +The parser is responsible for parsing templ files into an object model. The types that make up the object model are in `types.go`. Automatic formatting of the types is tested in `types_test.go`. + +A templ file is parsed into the `TemplateFile` struct object model. + +```go +type TemplateFile struct { + // Header contains comments or whitespace at the top of the file. + Header []GoExpression + // Package expression. + Package Package + // Nodes in the file. + Nodes []TemplateFileNode +} +``` + +Parsers are individually tested using two types of unit test. + +One test covers the successful parsing of text into an object. For example, the `HTMLCommentParser` test checks for successful patterns. + +```go +func TestHTMLCommentParser(t *testing.T) { + var tests = []struct { + name string + input string + expected HTMLComment + }{ + { + name: "comment - single line", + input: ``, + expected: HTMLComment{ + Contents: " single line comment ", + }, + }, + { + name: "comment - no whitespace", + input: ``, + expected: HTMLComment{ + Contents: "no whitespace between sequence open and close", + }, + }, + { + name: "comment - multiline", + input: ``, + expected: HTMLComment{ + Contents: ` multiline + comment + `, + }, + }, + { + name: "comment - with tag", + input: ``, + expected: HTMLComment{ + Contents: `

tag

`, + }, + }, + { + name: "comments can contain tags", + input: ``, + expected: HTMLComment{ + Contents: `
hello world
`, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := htmlComment.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Errorf(diff) + } + }) + } +} +``` + +Alongside each success test, is a similar test to check that invalid syntax is detected. + +```go +func TestHTMLCommentParserErrors(t *testing.T) { + var tests = []struct { + name string + input string + expected error + }{ + { + name: "unclosed HTML comment", + input: `' not found", + parse.Position{ + Index: 26, + Line: 0, + Col: 26, + }), + }, + { + name: "comment in comment", + input: ` -->`, + expected: parse.Error("comment contains invalid sequence '--'", parse.Position{ + Index: 8, + Line: 0, + Col: 8, + }), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + _, _, err := htmlComment.Parse(input) + if diff := cmp.Diff(tt.expected, err); diff != "" { + t.Error(diff) + } + }) + } +} +``` + +### Generator + +The generator takes the object model and writes out Go code that produces the expected output. Any changes to Go code output by templ are made in this area. + +Testing of the generator is carried out by creating a templ file, and a matching expected output file. + +For example, `./generator/test-a-href` contains a templ file of: + +```templ +package testahref + +templ render() { + Ignored + Sanitized + Unsanitized +} +``` + +It also contains an expected output file. + +```html +Ignored +Sanitized +Unsanitized +``` + +These tests contribute towards the code coverage metrics by building an instrumented test CLI program. See the `test-cover` task in the `README.md` file. + +### CLI + +The command line interface for templ is used to generate Go code from templ files, format templ files, and run the LSP. + +The code for this is at `./cmd/templ`. + +Testing of the templ command line is done with unit tests to check the argument parsing. + +The `templ generate` command is tested by generating templ files in the project, and testing that the expected output HTML is present. + +### Runtime + +The runtime is used by generated code, and by template authors, to serve template content over HTTP, and to carry out various operations. + +It is in the root directory of the project at `./runtime.go`. The runtime is unit tested, as well as being tested as part of the `generate` tests. + +### LSP + +The LSP is structured within the command line interface, and proxies commands through to the `gopls` LSP. + +### Docs + +The docs are a Docusaurus project at `./docs`. + +## Coding + +### Build tasks + +templ uses the `xc` task runner - https://github.com/joerdav/xc + +If you run `xc` you can get see a list of the development tasks that can be run, or you can read the `README.md` file and see the `Tasks` section. + +The most useful tasks for local development are: + +* `install-snapshot` - this builds the templ CLI and installs it into `~/bin`. Ensure that this is in your path. +* `test` - this regenerates all templates, and runs the unit tests. +* `fmt` - run the `gofmt` tool to format all Go code. +* `lint` - run the same linting as run in the CI process. +* `docs-run` - run the Docusaurus documentation site. + +### Commit messages + +The project using https://www.conventionalcommits.org/en/v1.0.0/ + +Examples: + +* `feat: support Go comments in templates, fixes #234"` + +### Coding style + +* Reduce nesting - i.e. prefer early returns over an `else` block, as per https://danp.net/posts/reducing-go-nesting/ or https://go.dev/doc/effective_go#if +* Use line breaks to separate "paragraphs" of code - don't use line breaks in between lines, or at the start/end of functions etc. +* Use the `fmt` and `lint` build tasks to format and lint your code before submitting a PR. + diff --git a/templ/LICENSE b/templ/LICENSE new file mode 100644 index 0000000..15e6fb8 --- /dev/null +++ b/templ/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Adrian Hesketh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/templ/README.md b/templ/README.md new file mode 100644 index 0000000..60d2f67 --- /dev/null +++ b/templ/README.md @@ -0,0 +1,184 @@ +![templ](https://github.com/a-h/templ/raw/main/templ.png) + +## An HTML templating language for Go that has great developer tooling. + +![templ](ide-demo.gif) + + +## Documentation + +See user documentation at https://templ.guide + +

+Go Reference +xc compatible +Go Coverage +Go Report Card +

+ +## Tasks + +### build + +Build a local version. + +```sh +go run ./get-version > .version +cd cmd/templ +go build +``` + +### install-snapshot + +Build and install current version. + +```sh +# Remove templ from the non-standard ~/bin/templ path +# that this command previously used. +rm -f ~/bin/templ +# Clear LSP logs. +rm -f cmd/templ/lspcmd/*.txt +# Update version. +go run ./get-version > .version +# Install to $GOPATH/bin or $HOME/go/bin +cd cmd/templ && go install +``` + +### build-snapshot + +Use goreleaser to build the command line binary using goreleaser. + +```sh +goreleaser build --snapshot --clean +``` + +### generate + +Run templ generate using local version. + +```sh +go run ./cmd/templ generate -include-version=false +``` + +### test + +Run Go tests. + +```sh +go run ./get-version > .version +go run ./cmd/templ generate -include-version=false +go test ./... +``` + +### test-short + +Run Go tests. + +```sh +go run ./get-version > .version +go run ./cmd/templ generate -include-version=false +go test ./... -short +``` + +### test-cover + +Run Go tests. + +```sh +# Create test profile directories. +mkdir -p coverage/fmt +mkdir -p coverage/generate +mkdir -p coverage/version +mkdir -p coverage/unit +# Build the test binary. +go build -cover -o ./coverage/templ-cover ./cmd/templ +# Run the covered generate command. +GOCOVERDIR=coverage/fmt ./coverage/templ-cover fmt . +GOCOVERDIR=coverage/generate ./coverage/templ-cover generate -include-version=false +GOCOVERDIR=coverage/version ./coverage/templ-cover version +# Run the unit tests. +go test -cover ./... -coverpkg ./... -args -test.gocoverdir="$PWD/coverage/unit" +# Display the combined percentage. +go tool covdata percent -i=./coverage/fmt,./coverage/generate,./coverage/version,./coverage/unit +# Generate a text coverage profile for tooling to use. +go tool covdata textfmt -i=./coverage/fmt,./coverage/generate,./coverage/version,./coverage/unit -o coverage.out +# Print total +go tool cover -func coverage.out | grep total +``` + +### test-cover-watch + +```sh +gotestsum --watch -- -coverprofile=coverage.out +``` + +### test-fuzz + +```sh +./parser/v2/fuzz.sh +./parser/v2/goexpression/fuzz.sh +``` + +### benchmark + +Run benchmarks. + +```sh +go run ./cmd/templ generate -include-version=false && go test ./... -bench=. -benchmem +``` + +### fmt + +Format all Go and templ code. + +```sh +gofmt -s -w . +go run ./cmd/templ fmt . +``` + +### lint + +Run the lint operations that are run as part of the CI. + +```sh +golangci-lint run --verbose +``` + +### ensure-generated + +Ensure that templ files have been generated with the local version of templ, and that those files have been added to git. + +Requires: generate + +```sh +git diff --exit-code +``` + +### push-release-tag + +Push a semantic version number to GitHub to trigger the release process. + +```sh +./push-tag.sh +``` + +### docs-run + +Run the development server. + +Directory: docs + +```sh +npm run start +``` + +### docs-build + +Build production docs site. + +Directory: docs + +```sh +npm run build +``` + diff --git a/templ/SECURITY.md b/templ/SECURITY.md new file mode 100644 index 0000000..e8c820e --- /dev/null +++ b/templ/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Supported Versions + +The latest version of templ is supported. + +## Reporting a Vulnerability + +Use the "Security" tab in GitHub and fill out the "Report a vulnerability" form. diff --git a/templ/benchmarks/react/.gitignore b/templ/benchmarks/react/.gitignore new file mode 100644 index 0000000..36abe80 --- /dev/null +++ b/templ/benchmarks/react/.gitignore @@ -0,0 +1,3 @@ +index.js +node_modules + diff --git a/templ/benchmarks/react/README.md b/templ/benchmarks/react/README.md new file mode 100644 index 0000000..409c608 --- /dev/null +++ b/templ/benchmarks/react/README.md @@ -0,0 +1,23 @@ +# React benchmark + +## Tasks + +### install + +``` +npm i +``` + +### build + +```sh +npm run build +``` + +### run + +requires: build + +```sh +npm start +``` diff --git a/templ/benchmarks/react/package-lock.json b/templ/benchmarks/react/package-lock.json new file mode 100644 index 0000000..1209fc9 --- /dev/null +++ b/templ/benchmarks/react/package-lock.json @@ -0,0 +1,719 @@ +{ + "name": "react-benchmark", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "react-benchmark", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "benchmark": "^2.1.4", + "esbuild": "0.19.2", + "microtime": "^3.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", + "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", + "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", + "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", + "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", + "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", + "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", + "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", + "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", + "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", + "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", + "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", + "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", + "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", + "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", + "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", + "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", + "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", + "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", + "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", + "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", + "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", + "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "node_modules/esbuild": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz", + "integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.19.2", + "@esbuild/android-arm64": "0.19.2", + "@esbuild/android-x64": "0.19.2", + "@esbuild/darwin-arm64": "0.19.2", + "@esbuild/darwin-x64": "0.19.2", + "@esbuild/freebsd-arm64": "0.19.2", + "@esbuild/freebsd-x64": "0.19.2", + "@esbuild/linux-arm": "0.19.2", + "@esbuild/linux-arm64": "0.19.2", + "@esbuild/linux-ia32": "0.19.2", + "@esbuild/linux-loong64": "0.19.2", + "@esbuild/linux-mips64el": "0.19.2", + "@esbuild/linux-ppc64": "0.19.2", + "@esbuild/linux-riscv64": "0.19.2", + "@esbuild/linux-s390x": "0.19.2", + "@esbuild/linux-x64": "0.19.2", + "@esbuild/netbsd-x64": "0.19.2", + "@esbuild/openbsd-x64": "0.19.2", + "@esbuild/sunos-x64": "0.19.2", + "@esbuild/win32-arm64": "0.19.2", + "@esbuild/win32-ia32": "0.19.2", + "@esbuild/win32-x64": "0.19.2" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/microtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.0.0.tgz", + "integrity": "sha512-SirJr7ZL4ow2iWcb54bekS4aWyBQNVcEDBiwAz9D/sTgY59A+uE8UJU15cp5wyZmPBwg/3zf8lyCJ5NUe1nVlQ==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^1.2.0", + "node-gyp-build": "^3.8.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" + }, + "node_modules/node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + } + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", + "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", + "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", + "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", + "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", + "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", + "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", + "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", + "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", + "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", + "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", + "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", + "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", + "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", + "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", + "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", + "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", + "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", + "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", + "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", + "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", + "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", + "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", + "optional": true + }, + "benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", + "requires": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, + "esbuild": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz", + "integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==", + "requires": { + "@esbuild/android-arm": "0.19.2", + "@esbuild/android-arm64": "0.19.2", + "@esbuild/android-x64": "0.19.2", + "@esbuild/darwin-arm64": "0.19.2", + "@esbuild/darwin-x64": "0.19.2", + "@esbuild/freebsd-arm64": "0.19.2", + "@esbuild/freebsd-x64": "0.19.2", + "@esbuild/linux-arm": "0.19.2", + "@esbuild/linux-arm64": "0.19.2", + "@esbuild/linux-ia32": "0.19.2", + "@esbuild/linux-loong64": "0.19.2", + "@esbuild/linux-mips64el": "0.19.2", + "@esbuild/linux-ppc64": "0.19.2", + "@esbuild/linux-riscv64": "0.19.2", + "@esbuild/linux-s390x": "0.19.2", + "@esbuild/linux-x64": "0.19.2", + "@esbuild/netbsd-x64": "0.19.2", + "@esbuild/openbsd-x64": "0.19.2", + "@esbuild/sunos-x64": "0.19.2", + "@esbuild/win32-arm64": "0.19.2", + "@esbuild/win32-ia32": "0.19.2", + "@esbuild/win32-x64": "0.19.2" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "microtime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/microtime/-/microtime-3.0.0.tgz", + "integrity": "sha512-SirJr7ZL4ow2iWcb54bekS4aWyBQNVcEDBiwAz9D/sTgY59A+uE8UJU15cp5wyZmPBwg/3zf8lyCJ5NUe1nVlQ==", + "requires": { + "node-addon-api": "^1.2.0", + "node-gyp-build": "^3.8.0" + } + }, + "node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" + }, + "node-gyp-build": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.9.0.tgz", + "integrity": "sha512-zLcTg6P4AbcHPq465ZMFNXx7XpKKJh+7kkN699NiQWisR2uWYOWNWqRHAmbnmKiL4e9aLSlmy5U7rEMUXV59+A==" + }, + "platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==" + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + } + } +} diff --git a/templ/benchmarks/react/package.json b/templ/benchmarks/react/package.json new file mode 100644 index 0000000..d234ac7 --- /dev/null +++ b/templ/benchmarks/react/package.json @@ -0,0 +1,19 @@ +{ + "name": "react-benchmark", + "version": "1.0.0", + "description": "", + "main": "./src/index.jsx", + "scripts": { + "build": "esbuild ./src/index.jsx --bundle --outfile=index.js", + "start": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "benchmark": "^2.1.4", + "esbuild": "0.19.2", + "microtime": "^3.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } +} diff --git a/templ/benchmarks/react/src/index.jsx b/templ/benchmarks/react/src/index.jsx new file mode 100644 index 0000000..b72b305 --- /dev/null +++ b/templ/benchmarks/react/src/index.jsx @@ -0,0 +1,34 @@ +import * as React from 'react' +import * as Server from 'react-dom/server' +import Benchmark from 'benchmark'; + +const component = (p) => +
+

{p.Name}

+
+ +
+


+
; + +const p = { + Name: "Luiz Bonfa", + Email: "luiz@example.com", +}; + +// Benchmark. +// Outputs... +// Render test x 114,131 ops/sec ±0.27% (97 runs sampled) +// There are 1,000,000,000 nanoseconds in a second. +// 1,000,000,000ns / 114,131 ops = 8,757.5 ns per operation. +// The templ equivalent is 340 ns per operation. +const suite = new Benchmark.Suite; + +const test = suite.add('Render test', + () => Server.renderToString(component(p))) + +test.on('cycle', (event) => { + console.log(String(event.target)); +}); + +test.run(); diff --git a/templ/benchmarks/templ/README.md b/templ/benchmarks/templ/README.md new file mode 100644 index 0000000..9275b01 --- /dev/null +++ b/templ/benchmarks/templ/README.md @@ -0,0 +1,27 @@ +# templ benchmark + +Used to test code generation strategies for improvements to render time. + +## Tasks + +### run + +``` +go test -bench . +``` + +## Results as of 2023-08-17 + +``` +go test -bench . +goos: darwin +goarch: arm64 +pkg: github.com/a-h/templ/benchmarks/templ +BenchmarkTempl-10 3291883 369.1 ns/op 536 B/op 6 allocs/op +BenchmarkGoTemplate-10 481052 2475 ns/op 1400 B/op 38 allocs/op +BenchmarkIOWriteString-10 20353198 56.64 ns/op 320 B/op 1 allocs/op +PASS +ok github.com/a-h/templ/benchmarks/templ 4.650s +``` + +React comes in at 1,000,000,000ns / 114,131 ops/s = 8,757.5 ns per operation. diff --git a/templ/benchmarks/templ/data.go b/templ/benchmarks/templ/data.go new file mode 100644 index 0000000..adc32dc --- /dev/null +++ b/templ/benchmarks/templ/data.go @@ -0,0 +1,6 @@ +package testhtml + +type Person struct { + Name string + Email string +} diff --git a/templ/benchmarks/templ/render_test.go b/templ/benchmarks/templ/render_test.go new file mode 100644 index 0000000..cecb523 --- /dev/null +++ b/templ/benchmarks/templ/render_test.go @@ -0,0 +1,87 @@ +package testhtml + +import ( + "context" + "html/template" + "io" + "strings" + "testing" + + _ "embed" + + "github.com/a-h/templ/parser/v2" +) + +func BenchmarkTemplRender(b *testing.B) { + b.ReportAllocs() + t := Render(Person{ + Name: "Luiz Bonfa", + Email: "luiz@example.com", + }) + + w := new(strings.Builder) + for i := 0; i < b.N; i++ { + err := t.Render(context.Background(), w) + if err != nil { + b.Errorf("failed to render: %v", err) + } + w.Reset() + } +} + +//go:embed template.templ +var parserBenchmarkTemplate string + +func BenchmarkTemplParser(b *testing.B) { + for i := 0; i < b.N; i++ { + tf, err := parser.ParseString(parserBenchmarkTemplate) + if err != nil { + b.Fatal(err) + } + if tf.Package.Expression.Value == "" { + b.Fatal("unexpected nil template") + } + } +} + +var goTemplate = template.Must(template.New("example").Parse(`
+

{{.Name}}

+
+
+ email:{{.Email}}
+
+
+
+
+
+`)) + +func BenchmarkGoTemplateRender(b *testing.B) { + w := new(strings.Builder) + person := Person{ + Name: "Luiz Bonfa", + Email: "luiz@exapmle.com", + } + b.ReportAllocs() + for i := 0; i < b.N; i++ { + err := goTemplate.Execute(w, person) + if err != nil { + b.Errorf("failed to render: %v", err) + } + w.Reset() + } +} + +const html = `

Luiz Bonfa




` + +func BenchmarkIOWriteString(b *testing.B) { + b.ReportAllocs() + w := new(strings.Builder) + for i := 0; i < b.N; i++ { + _, err := io.WriteString(w, html) + if err != nil { + b.Errorf("failed to render: %v", err) + } + w.Reset() + } +} diff --git a/templ/benchmarks/templ/template.templ b/templ/benchmarks/templ/template.templ new file mode 100644 index 0000000..54ac5f2 --- /dev/null +++ b/templ/benchmarks/templ/template.templ @@ -0,0 +1,13 @@ +package testhtml + +templ Render(p Person) { +
+

{ p.Name }

+
` }> + +
+
+
+
+
+} diff --git a/templ/benchmarks/templ/template_templ.go b/templ/benchmarks/templ/template_templ.go new file mode 100644 index 0000000..2638d39 --- /dev/null +++ b/templ/benchmarks/templ/template_templ.go @@ -0,0 +1,118 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testhtml + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Render(p Person) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(p.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/benchmarks/templ/template.templ`, Line: 5, Col: 14} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

`) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/benchmarks/templ/template.templ`, Line: 6, Col: 104} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">


") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cfg/cfg.go b/templ/cfg/cfg.go new file mode 100644 index 0000000..0ea880d --- /dev/null +++ b/templ/cfg/cfg.go @@ -0,0 +1,20 @@ +// This package is inspired by the GOEXPERIMENT approach of allowing feature flags for experimenting with breaking changes. +package cfg + +import ( + "os" + "strings" +) + +type Flags struct{} + +var Experiment = parse() + +func parse() *Flags { + m := map[string]bool{} + for _, f := range strings.Split(os.Getenv("TEMPL_EXPERIMENT"), ",") { + m[strings.ToLower(f)] = true + } + + return &Flags{} +} diff --git a/templ/cmd/templ/fmtcmd/main.go b/templ/cmd/templ/fmtcmd/main.go new file mode 100644 index 0000000..2f2b7fc --- /dev/null +++ b/templ/cmd/templ/fmtcmd/main.go @@ -0,0 +1,166 @@ +package fmtcmd + +import ( + "bytes" + "fmt" + "io" + "log/slog" + "os" + "runtime" + "sync" + "time" + + "github.com/a-h/templ/cmd/templ/imports" + "github.com/a-h/templ/cmd/templ/processor" + parser "github.com/a-h/templ/parser/v2" + "github.com/natefinch/atomic" +) + +type Arguments struct { + FailIfChanged bool + ToStdout bool + StdinFilepath string + Files []string + WorkerCount int +} + +func Run(log *slog.Logger, stdin io.Reader, stdout io.Writer, args Arguments) (err error) { + // If no files are provided, read from stdin and write to stdout. + if len(args.Files) == 0 { + out, _ := format(writeToWriter(stdout), readFromReader(stdin, args.StdinFilepath), true) + return out + } + process := func(fileName string) (error, bool) { + read := readFromFile(fileName) + write := writeToFile + if args.ToStdout { + write = writeToWriter(stdout) + } + writeIfUnchanged := args.ToStdout + return format(write, read, writeIfUnchanged) + } + dir := args.Files[0] + return NewFormatter(log, dir, process, args.WorkerCount, args.FailIfChanged).Run() +} + +type Formatter struct { + Log *slog.Logger + Dir string + Process func(fileName string) (error, bool) + WorkerCount int + FailIfChange bool +} + +func NewFormatter(log *slog.Logger, dir string, process func(fileName string) (error, bool), workerCount int, failIfChange bool) *Formatter { + f := &Formatter{ + Log: log, + Dir: dir, + Process: process, + WorkerCount: workerCount, + FailIfChange: failIfChange, + } + if f.WorkerCount == 0 { + f.WorkerCount = runtime.NumCPU() + } + return f +} + +func (f *Formatter) Run() (err error) { + changesMade := 0 + start := time.Now() + results := make(chan processor.Result) + f.Log.Debug("Walking directory", slog.String("path", f.Dir)) + go processor.Process(f.Dir, f.Process, f.WorkerCount, results) + var successCount, errorCount int + for r := range results { + if r.ChangesMade { + changesMade += 1 + } + if r.Error != nil { + f.Log.Error(r.FileName, slog.Any("error", r.Error)) + errorCount++ + continue + } + f.Log.Debug(r.FileName, slog.Duration("duration", r.Duration)) + successCount++ + } + + if f.FailIfChange && changesMade > 0 { + f.Log.Error("Templates were valid but not properly formatted", slog.Int("count", successCount+errorCount), slog.Int("changed", changesMade), slog.Int("errors", errorCount), slog.Duration("duration", time.Since(start))) + return fmt.Errorf("templates were not formatted properly") + } + + f.Log.Info("Format Complete", slog.Int("count", successCount+errorCount), slog.Int("errors", errorCount), slog.Int("changed", changesMade), slog.Duration("duration", time.Since(start))) + + if errorCount > 0 { + return fmt.Errorf("formatting failed") + } + + return +} + +type reader func() (fileName, src string, err error) + +func readFromReader(r io.Reader, stdinFilepath string) func() (fileName, src string, err error) { + return func() (fileName, src string, err error) { + b, err := io.ReadAll(r) + if err != nil { + return "", "", fmt.Errorf("failed to read stdin: %w", err) + } + return stdinFilepath, string(b), nil + } +} + +func readFromFile(name string) reader { + return func() (fileName, src string, err error) { + b, err := os.ReadFile(name) + if err != nil { + return "", "", fmt.Errorf("failed to read file %q: %w", fileName, err) + } + return name, string(b), nil + } +} + +type writer func(fileName, tgt string) error + +var mu sync.Mutex + +func writeToWriter(w io.Writer) func(fileName, tgt string) error { + return func(fileName, tgt string) error { + mu.Lock() + defer mu.Unlock() + _, err := w.Write([]byte(tgt)) + return err + } +} + +func writeToFile(fileName, tgt string) error { + return atomic.WriteFile(fileName, bytes.NewBufferString(tgt)) +} + +func format(write writer, read reader, writeIfUnchanged bool) (err error, fileChanged bool) { + fileName, src, err := read() + if err != nil { + return err, false + } + t, err := parser.ParseString(src) + if err != nil { + return err, false + } + t.Filepath = fileName + t, err = imports.Process(t) + if err != nil { + return err, false + } + w := new(bytes.Buffer) + if err = t.Write(w); err != nil { + return fmt.Errorf("formatting error: %w", err), false + } + + fileChanged = (src != w.String()) + + if !writeIfUnchanged && !fileChanged { + return nil, fileChanged + } + return write(fileName, w.String()), fileChanged +} diff --git a/templ/cmd/templ/fmtcmd/main_test.go b/templ/cmd/templ/fmtcmd/main_test.go new file mode 100644 index 0000000..9a70f36 --- /dev/null +++ b/templ/cmd/templ/fmtcmd/main_test.go @@ -0,0 +1,163 @@ +package fmtcmd + +import ( + _ "embed" + "fmt" + "io" + "log/slog" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "golang.org/x/tools/txtar" +) + +//go:embed testdata.txtar +var testDataTxTar []byte + +type testProject struct { + dir string + cleanup func() + testFiles map[string]testFile +} + +type testFile struct { + name string + input, expected string +} + +func setupProjectDir() (tp testProject, err error) { + tp.dir, err = os.MkdirTemp("", "fmtcmd_test_*") + if err != nil { + return tp, fmt.Errorf("failed to make test dir: %w", err) + } + tp.testFiles = make(map[string]testFile) + testData := txtar.Parse(testDataTxTar) + for i := 0; i < len(testData.Files); i += 2 { + file := testData.Files[i] + err = os.WriteFile(filepath.Join(tp.dir, file.Name), file.Data, 0660) + if err != nil { + return tp, fmt.Errorf("failed to write file: %w", err) + } + tp.testFiles[file.Name] = testFile{ + name: filepath.Join(tp.dir, file.Name), + input: string(file.Data), + expected: string(testData.Files[i+1].Data), + } + } + tp.cleanup = func() { + os.RemoveAll(tp.dir) + } + return tp, nil +} + +func TestFormat(t *testing.T) { + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + t.Run("can format a single file from stdin to stdout", func(t *testing.T) { + tp, err := setupProjectDir() + if err != nil { + t.Fatalf("failed to setup project dir: %v", err) + } + defer tp.cleanup() + stdin := strings.NewReader(tp.testFiles["a.templ"].input) + stdout := new(strings.Builder) + if err = Run(log, stdin, stdout, Arguments{ + ToStdout: true, + }); err != nil { + t.Fatalf("failed to run format command: %v", err) + } + if diff := cmp.Diff(tp.testFiles["a.templ"].expected, stdout.String()); diff != "" { + t.Error(diff) + } + }) + t.Run("can process a single file to stdout", func(t *testing.T) { + tp, err := setupProjectDir() + if err != nil { + t.Fatalf("failed to setup project dir: %v", err) + } + defer tp.cleanup() + stdout := new(strings.Builder) + if err = Run(log, nil, stdout, Arguments{ + ToStdout: true, + Files: []string{ + tp.testFiles["a.templ"].name, + }, + FailIfChanged: false, + }); err != nil { + t.Fatalf("failed to run format command: %v", err) + } + if diff := cmp.Diff(tp.testFiles["a.templ"].expected, stdout.String()); diff != "" { + t.Error(diff) + } + }) + t.Run("can process a single file in place", func(t *testing.T) { + tp, err := setupProjectDir() + if err != nil { + t.Fatalf("failed to setup project dir: %v", err) + } + defer tp.cleanup() + if err = Run(log, nil, nil, Arguments{ + Files: []string{ + tp.testFiles["a.templ"].name, + }, + FailIfChanged: false, + }); err != nil { + t.Fatalf("failed to run format command: %v", err) + } + data, err := os.ReadFile(tp.testFiles["a.templ"].name) + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + if diff := cmp.Diff(tp.testFiles["a.templ"].expected, string(data)); diff != "" { + t.Error(diff) + } + }) + + t.Run("fails when fail flag used and change occurs", func(t *testing.T) { + tp, err := setupProjectDir() + if err != nil { + t.Fatalf("failed to setup project dir: %v", err) + } + defer tp.cleanup() + if err = Run(log, nil, nil, Arguments{ + Files: []string{ + tp.testFiles["a.templ"].name, + }, + FailIfChanged: true, + }); err == nil { + t.Fatal("command should have exited with an error and did not") + } + data, err := os.ReadFile(tp.testFiles["a.templ"].name) + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + if diff := cmp.Diff(tp.testFiles["a.templ"].expected, string(data)); diff != "" { + t.Error(diff) + } + }) + + t.Run("passes when fail flag used and no change occurs", func(t *testing.T) { + tp, err := setupProjectDir() + if err != nil { + t.Fatalf("failed to setup project dir: %v", err) + } + defer tp.cleanup() + if err = Run(log, nil, nil, Arguments{ + Files: []string{ + tp.testFiles["c.templ"].name, + }, + FailIfChanged: true, + }); err != nil { + t.Fatalf("failed to run format command: %v", err) + } + data, err := os.ReadFile(tp.testFiles["c.templ"].name) + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + if diff := cmp.Diff(tp.testFiles["c.templ"].expected, string(data)); diff != "" { + t.Error(diff) + } + }) +} diff --git a/templ/cmd/templ/fmtcmd/testdata.txtar b/templ/cmd/templ/fmtcmd/testdata.txtar new file mode 100644 index 0000000..8041fce --- /dev/null +++ b/templ/cmd/templ/fmtcmd/testdata.txtar @@ -0,0 +1,54 @@ +-- a.templ -- +package test + +templ a() { +

A +

+} +-- a.templ -- +package test + +templ a() { +
+

+ A +

+
+} +-- b.templ -- +package test + +templ b() { +

B +

+} +-- b.templ -- +package test + +templ b() { +
+

+ B +

+
+} +-- c.templ -- +package test + +templ c() { +
+

+ C +

+
+} +-- c.templ -- +package test + +templ c() { +
+

+ C +

+
+} diff --git a/templ/cmd/templ/generatecmd/cmd.go b/templ/cmd/templ/generatecmd/cmd.go new file mode 100644 index 0000000..169cc06 --- /dev/null +++ b/templ/cmd/templ/generatecmd/cmd.go @@ -0,0 +1,403 @@ +package generatecmd + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "regexp" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/a-h/templ" + "github.com/a-h/templ/cmd/templ/generatecmd/modcheck" + "github.com/a-h/templ/cmd/templ/generatecmd/proxy" + "github.com/a-h/templ/cmd/templ/generatecmd/run" + "github.com/a-h/templ/cmd/templ/generatecmd/watcher" + "github.com/a-h/templ/generator" + "github.com/cenkalti/backoff/v4" + "github.com/cli/browser" + "github.com/fsnotify/fsnotify" +) + +const defaultWatchPattern = `(.+\.go$)|(.+\.templ$)|(.+_templ\.txt$)` + +func NewGenerate(log *slog.Logger, args Arguments) (g *Generate, err error) { + g = &Generate{ + Log: log, + Args: &args, + } + if g.Args.WorkerCount == 0 { + g.Args.WorkerCount = runtime.NumCPU() + } + if g.Args.WatchPattern == "" { + g.Args.WatchPattern = defaultWatchPattern + } + g.WatchPattern, err = regexp.Compile(g.Args.WatchPattern) + if err != nil { + return nil, fmt.Errorf("failed to compile watch pattern %q: %w", g.Args.WatchPattern, err) + } + return g, nil +} + +type Generate struct { + Log *slog.Logger + Args *Arguments + WatchPattern *regexp.Regexp +} + +type GenerationEvent struct { + Event fsnotify.Event + Updated bool + GoUpdated bool + TextUpdated bool +} + +func (cmd Generate) Run(ctx context.Context) (err error) { + if cmd.Args.NotifyProxy { + return proxy.NotifyProxy(cmd.Args.ProxyBind, cmd.Args.ProxyPort) + } + if cmd.Args.Watch && cmd.Args.FileName != "" { + return fmt.Errorf("cannot watch a single file, remove the -f or -watch flag") + } + writingToWriter := cmd.Args.FileWriter != nil + if cmd.Args.FileName == "" && writingToWriter { + return fmt.Errorf("only a single file can be output to stdout, add the -f flag to specify the file to generate code for") + } + // Default to writing to files. + if cmd.Args.FileWriter == nil { + cmd.Args.FileWriter = FileWriter + } + if cmd.Args.PPROFPort > 0 { + go func() { + _ = http.ListenAndServe(fmt.Sprintf("localhost:%d", cmd.Args.PPROFPort), nil) + }() + } + + // Use absolute path. + if !path.IsAbs(cmd.Args.Path) { + cmd.Args.Path, err = filepath.Abs(cmd.Args.Path) + if err != nil { + return fmt.Errorf("failed to get absolute path: %w", err) + } + } + + // Configure generator. + var opts []generator.GenerateOpt + if cmd.Args.IncludeVersion { + opts = append(opts, generator.WithVersion(templ.Version())) + } + if cmd.Args.IncludeTimestamp { + opts = append(opts, generator.WithTimestamp(time.Now())) + } + + // Check the version of the templ module. + if err := modcheck.Check(cmd.Args.Path); err != nil { + cmd.Log.Warn("templ version check: " + err.Error()) + } + + fseh := NewFSEventHandler( + cmd.Log, + cmd.Args.Path, + cmd.Args.Watch, + opts, + cmd.Args.GenerateSourceMapVisualisations, + cmd.Args.KeepOrphanedFiles, + cmd.Args.FileWriter, + cmd.Args.Lazy, + ) + + // If we're processing a single file, don't bother setting up the channels/multithreaing. + if cmd.Args.FileName != "" { + _, err = fseh.HandleEvent(ctx, fsnotify.Event{ + Name: cmd.Args.FileName, + Op: fsnotify.Create, + }) + return err + } + + // Start timer. + start := time.Now() + + // Create channels: + // For the initial filesystem walk and subsequent (optional) fsnotify events. + events := make(chan fsnotify.Event) + // Count of events currently being processed by the event handler. + var eventsWG sync.WaitGroup + // Used to check that the event handler has completed. + var eventHandlerWG sync.WaitGroup + // For errs from the watcher. + errs := make(chan error) + // Tracks whether errors occurred during the generation process. + var errorCount atomic.Int64 + // For triggering actions after generation has completed. + postGeneration := make(chan *GenerationEvent, 256) + // Used to check that the post-generation handler has completed. + var postGenerationWG sync.WaitGroup + var postGenerationEventsWG sync.WaitGroup + + // Waitgroup for the push process. + var pushHandlerWG sync.WaitGroup + + // Start process to push events into the channel. + pushHandlerWG.Add(1) + go func() { + defer pushHandlerWG.Done() + defer close(events) + cmd.Log.Debug( + "Walking directory", + slog.String("path", cmd.Args.Path), + slog.Bool("devMode", cmd.Args.Watch), + ) + if err := watcher.WalkFiles(ctx, cmd.Args.Path, cmd.WatchPattern, events); err != nil { + cmd.Log.Error("WalkFiles failed, exiting", slog.Any("error", err)) + errs <- FatalError{Err: fmt.Errorf("failed to walk files: %w", err)} + return + } + if !cmd.Args.Watch { + cmd.Log.Debug("Dev mode not enabled, process can finish early") + return + } + cmd.Log.Info("Watching files") + rw, err := watcher.Recursive(ctx, cmd.Args.Path, cmd.WatchPattern, events, errs) + if err != nil { + cmd.Log.Error("Recursive watcher setup failed, exiting", slog.Any("error", err)) + errs <- FatalError{Err: fmt.Errorf("failed to setup recursive watcher: %w", err)} + return + } + cmd.Log.Debug("Waiting for context to be cancelled to stop watching files") + <-ctx.Done() + cmd.Log.Debug("Context cancelled, closing watcher") + if err := rw.Close(); err != nil { + cmd.Log.Error("Failed to close watcher", slog.Any("error", err)) + } + cmd.Log.Debug("Waiting for events to be processed") + eventsWG.Wait() + cmd.Log.Debug( + "All pending events processed, waiting for pending post-generation events to complete", + ) + postGenerationEventsWG.Wait() + cmd.Log.Debug( + "All post-generation events processed, deleting watch mode text files", + slog.Int64("errorCount", errorCount.Load()), + ) + + fileEvents := make(chan fsnotify.Event) + go func() { + if err := watcher.WalkFiles(ctx, cmd.Args.Path, cmd.WatchPattern, fileEvents); err != nil { + cmd.Log.Error("Post dev mode WalkFiles failed", slog.Any("error", err)) + errs <- FatalError{Err: fmt.Errorf("failed to walk files: %w", err)} + return + } + close(fileEvents) + }() + for event := range fileEvents { + if strings.HasSuffix(event.Name, "_templ.txt") { + if err = os.Remove(event.Name); err != nil { + cmd.Log.Warn("Failed to remove watch mode text file", slog.Any("error", err)) + } + } + } + }() + + // Start process to handle events. + eventHandlerWG.Add(1) + sem := make(chan struct{}, cmd.Args.WorkerCount) + go func() { + defer eventHandlerWG.Done() + defer close(postGeneration) + cmd.Log.Debug("Starting event handler") + for event := range events { + eventsWG.Add(1) + sem <- struct{}{} + go func(event fsnotify.Event) { + cmd.Log.Debug("Processing file", slog.String("file", event.Name)) + defer eventsWG.Done() + defer func() { <-sem }() + r, err := fseh.HandleEvent(ctx, event) + if err != nil { + errs <- err + } + if !(r.GoUpdated || r.TextUpdated) { + cmd.Log.Debug("File not updated", slog.String("file", event.Name)) + return + } + e := &GenerationEvent{ + Event: event, + Updated: r.Updated, + GoUpdated: r.GoUpdated, + TextUpdated: r.TextUpdated, + } + cmd.Log.Debug("File updated", slog.String("file", event.Name)) + postGeneration <- e + }(event) + } + // Wait for all events to be processed before closing. + eventsWG.Wait() + }() + + // Start process to handle post-generation events. + var updates int + postGenerationWG.Add(1) + var firstPostGenerationExecuted bool + go func() { + defer close(errs) + defer postGenerationWG.Done() + cmd.Log.Debug("Starting post-generation handler") + timeout := time.NewTimer(time.Hour * 24 * 365) + var goUpdated, textUpdated bool + var p *proxy.Handler + for { + select { + case ge := <-postGeneration: + if ge == nil { + cmd.Log.Debug("Post-generation event channel closed, exiting") + return + } + goUpdated = goUpdated || ge.GoUpdated + textUpdated = textUpdated || ge.TextUpdated + if goUpdated || textUpdated { + updates++ + } + // Reset timer. + if !timeout.Stop() { + <-timeout.C + } + timeout.Reset(time.Millisecond * 100) + case <-timeout.C: + if !goUpdated && !textUpdated { + // Nothing to process, reset timer and wait again. + timeout.Reset(time.Hour * 24 * 365) + break + } + postGenerationEventsWG.Add(1) + if cmd.Args.Command != "" && goUpdated { + cmd.Log.Debug("Executing command", slog.String("command", cmd.Args.Command)) + if cmd.Args.Watch { + os.Setenv("TEMPL_DEV_MODE", "true") + } + if _, err := run.Run(ctx, cmd.Args.Path, cmd.Args.Command); err != nil { + cmd.Log.Error("Error executing command", slog.Any("error", err)) + } + } + if !firstPostGenerationExecuted { + cmd.Log.Debug("First post-generation event received, starting proxy") + firstPostGenerationExecuted = true + p, err = cmd.StartProxy(ctx) + if err != nil { + cmd.Log.Error("Failed to start proxy", slog.Any("error", err)) + } + } + // Send server-sent event. + if p != nil && (textUpdated || goUpdated) { + cmd.Log.Debug("Sending reload event") + p.SendSSE("message", "reload") + } + postGenerationEventsWG.Done() + // Reset timer. + timeout.Reset(time.Millisecond * 100) + textUpdated = false + goUpdated = false + } + } + }() + + // Read errors. + for err := range errs { + if err == nil { + continue + } + if errors.Is(err, FatalError{}) { + cmd.Log.Debug("Fatal error, exiting") + return err + } + cmd.Log.Error("Error", slog.Any("error", err)) + errorCount.Add(1) + } + + // Wait for everything to complete. + cmd.Log.Debug("Waiting for push handler to complete") + pushHandlerWG.Wait() + cmd.Log.Debug("Waiting for event handler to complete") + eventHandlerWG.Wait() + cmd.Log.Debug("Waiting for post-generation handler to complete") + postGenerationWG.Wait() + if cmd.Args.Command != "" { + cmd.Log.Debug("Killing command", slog.String("command", cmd.Args.Command)) + if err := run.KillAll(); err != nil { + cmd.Log.Error("Error killing command", slog.Any("error", err)) + } + } + + // Check for errors after everything has completed. + if errorCount.Load() > 0 { + return fmt.Errorf("generation completed with %d errors", errorCount.Load()) + } + + cmd.Log.Info( + "Complete", + slog.Int("updates", updates), + slog.Duration("duration", time.Since(start)), + ) + return nil +} + +func (cmd *Generate) StartProxy(ctx context.Context) (p *proxy.Handler, err error) { + if cmd.Args.Proxy == "" { + cmd.Log.Debug("No proxy URL specified, not starting proxy") + return nil, nil + } + var target *url.URL + target, err = url.Parse(cmd.Args.Proxy) + if err != nil { + return nil, FatalError{Err: fmt.Errorf("failed to parse proxy URL: %w", err)} + } + if cmd.Args.ProxyPort == 0 { + cmd.Args.ProxyPort = 7331 + } + if cmd.Args.ProxyBind == "" { + cmd.Args.ProxyBind = "127.0.0.1" + } + p = proxy.New(cmd.Log, cmd.Args.ProxyBind, cmd.Args.ProxyPort, target) + go func() { + cmd.Log.Info("Proxying", slog.String("from", p.URL), slog.String("to", p.Target.String())) + if err := http.ListenAndServe(fmt.Sprintf("%s:%d", cmd.Args.ProxyBind, cmd.Args.ProxyPort), p); err != nil { + cmd.Log.Error("Proxy failed", slog.Any("error", err)) + } + }() + if !cmd.Args.OpenBrowser { + cmd.Log.Debug("Not opening browser") + return p, nil + } + go func() { + cmd.Log.Debug("Waiting for proxy to be ready", slog.String("url", p.URL)) + backoff := backoff.NewExponentialBackOff() + backoff.InitialInterval = time.Second + var client http.Client + client.Timeout = 1 * time.Second + for { + if _, err := client.Get(p.URL); err == nil { + break + } + d := backoff.NextBackOff() + cmd.Log.Debug( + "Proxy not ready, retrying", + slog.String("url", p.URL), + slog.Any("backoff", d), + ) + time.Sleep(d) + } + if err := browser.OpenURL(p.URL); err != nil { + cmd.Log.Error("Failed to open browser", slog.Any("error", err)) + } + }() + return p, nil +} diff --git a/templ/cmd/templ/generatecmd/eventhandler.go b/templ/cmd/templ/generatecmd/eventhandler.go new file mode 100644 index 0000000..93ce332 --- /dev/null +++ b/templ/cmd/templ/generatecmd/eventhandler.go @@ -0,0 +1,366 @@ +package generatecmd + +import ( + "bufio" + "bytes" + "context" + "crypto/sha256" + "fmt" + "go/format" + "go/scanner" + "go/token" + "io" + "log/slog" + "os" + "path" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/a-h/templ/cmd/templ/visualize" + "github.com/a-h/templ/generator" + "github.com/a-h/templ/parser/v2" + "github.com/fsnotify/fsnotify" +) + +type FileWriterFunc func(name string, contents []byte) error + +func FileWriter(fileName string, contents []byte) error { + return os.WriteFile(fileName, contents, 0o644) +} + +func WriterFileWriter(w io.Writer) FileWriterFunc { + return func(_ string, contents []byte) error { + _, err := w.Write(contents) + return err + } +} + +func NewFSEventHandler( + log *slog.Logger, + dir string, + devMode bool, + genOpts []generator.GenerateOpt, + genSourceMapVis bool, + keepOrphanedFiles bool, + fileWriter FileWriterFunc, + lazy bool, +) *FSEventHandler { + if !path.IsAbs(dir) { + dir, _ = filepath.Abs(dir) + } + fseh := &FSEventHandler{ + Log: log, + dir: dir, + fileNameToLastModTime: make(map[string]time.Time), + fileNameToLastModTimeMutex: &sync.Mutex{}, + fileNameToError: make(map[string]struct{}), + fileNameToErrorMutex: &sync.Mutex{}, + fileNameToOutput: make(map[string]generator.GeneratorOutput), + fileNameToOutputMutex: &sync.Mutex{}, + devMode: devMode, + hashes: make(map[string][sha256.Size]byte), + hashesMutex: &sync.Mutex{}, + genOpts: genOpts, + genSourceMapVis: genSourceMapVis, + keepOrphanedFiles: keepOrphanedFiles, + writer: fileWriter, + lazy: lazy, + } + return fseh +} + +type FSEventHandler struct { + Log *slog.Logger + // dir is the root directory being processed. + dir string + fileNameToLastModTime map[string]time.Time + fileNameToLastModTimeMutex *sync.Mutex + fileNameToError map[string]struct{} + fileNameToErrorMutex *sync.Mutex + fileNameToOutput map[string]generator.GeneratorOutput + fileNameToOutputMutex *sync.Mutex + devMode bool + hashes map[string][sha256.Size]byte + hashesMutex *sync.Mutex + genOpts []generator.GenerateOpt + genSourceMapVis bool + Errors []error + keepOrphanedFiles bool + writer func(string, []byte) error + lazy bool +} + +type GenerateResult struct { + // Updated indicates that the file was updated. + Updated bool + // GoUpdated indicates that Go expressions were updated. + GoUpdated bool + // TextUpdated indicates that text literals were updated. + TextUpdated bool +} + +func (h *FSEventHandler) HandleEvent(ctx context.Context, event fsnotify.Event) (result GenerateResult, err error) { + // Handle _templ.go files. + if !event.Has(fsnotify.Remove) && strings.HasSuffix(event.Name, "_templ.go") { + _, err = os.Stat(strings.TrimSuffix(event.Name, "_templ.go") + ".templ") + if !os.IsNotExist(err) { + return GenerateResult{}, err + } + // File is orphaned. + if h.keepOrphanedFiles { + return GenerateResult{}, nil + } + h.Log.Debug("Deleting orphaned Go file", slog.String("file", event.Name)) + if err = os.Remove(event.Name); err != nil { + h.Log.Warn("Failed to remove orphaned file", slog.Any("error", err)) + } + return GenerateResult{Updated: true, GoUpdated: true, TextUpdated: false}, nil + } + // Handle _templ.txt files. + if !event.Has(fsnotify.Remove) && strings.HasSuffix(event.Name, "_templ.txt") { + if h.devMode { + // Don't delete the file in dev mode, ignore changes to it, since the .templ file + // must have been updated in order to trigger a change in the _templ.txt file. + return GenerateResult{Updated: false, GoUpdated: false, TextUpdated: false}, nil + } + h.Log.Debug("Deleting watch mode file", slog.String("file", event.Name)) + if err = os.Remove(event.Name); err != nil { + h.Log.Warn("Failed to remove watch mode text file", slog.Any("error", err)) + return GenerateResult{}, nil + } + return GenerateResult{}, nil + } + + // If the file hasn't been updated since the last time we processed it, ignore it. + lastModTime, updatedModTime := h.UpsertLastModTime(event.Name) + if !updatedModTime { + h.Log.Debug("Skipping file because it wasn't updated", slog.String("file", event.Name)) + return GenerateResult{}, nil + } + + // Process anything that isn't a templ file. + if !strings.HasSuffix(event.Name, ".templ") { + // If it's a Go file, mark it as updated. + if strings.HasSuffix(event.Name, ".go") { + result.GoUpdated = true + } + result.Updated = true + return result, nil + } + + // Handle templ files. + + // If the go file is newer than the templ file, skip generation, because it's up-to-date. + if h.lazy && goFileIsUpToDate(event.Name, lastModTime) { + h.Log.Debug("Skipping file because the Go file is up-to-date", slog.String("file", event.Name)) + return GenerateResult{}, nil + } + + // Start a processor. + start := time.Now() + var diag []parser.Diagnostic + result, diag, err = h.generate(ctx, event.Name) + if err != nil { + h.SetError(event.Name, true) + return result, fmt.Errorf("failed to generate code for %q: %w", event.Name, err) + } + if len(diag) > 0 { + for _, d := range diag { + h.Log.Warn(d.Message, + slog.String("from", fmt.Sprintf("%d:%d", d.Range.From.Line, d.Range.From.Col)), + slog.String("to", fmt.Sprintf("%d:%d", d.Range.To.Line, d.Range.To.Col)), + ) + } + return result, nil + } + if errorCleared, errorCount := h.SetError(event.Name, false); errorCleared { + h.Log.Info("Error cleared", slog.String("file", event.Name), slog.Int("errors", errorCount)) + } + h.Log.Debug("Generated code", slog.String("file", event.Name), slog.Duration("in", time.Since(start))) + + return result, nil +} + +func goFileIsUpToDate(templFileName string, templFileLastMod time.Time) (upToDate bool) { + goFileName := strings.TrimSuffix(templFileName, ".templ") + "_templ.go" + goFileInfo, err := os.Stat(goFileName) + if err != nil { + return false + } + return goFileInfo.ModTime().After(templFileLastMod) +} + +func (h *FSEventHandler) SetError(fileName string, hasError bool) (previouslyHadError bool, errorCount int) { + h.fileNameToErrorMutex.Lock() + defer h.fileNameToErrorMutex.Unlock() + _, previouslyHadError = h.fileNameToError[fileName] + delete(h.fileNameToError, fileName) + if hasError { + h.fileNameToError[fileName] = struct{}{} + } + return previouslyHadError, len(h.fileNameToError) +} + +func (h *FSEventHandler) UpsertLastModTime(fileName string) (modTime time.Time, updated bool) { + fileInfo, err := os.Stat(fileName) + if err != nil { + return modTime, false + } + h.fileNameToLastModTimeMutex.Lock() + defer h.fileNameToLastModTimeMutex.Unlock() + previousModTime := h.fileNameToLastModTime[fileName] + currentModTime := fileInfo.ModTime() + if !currentModTime.After(previousModTime) { + return currentModTime, false + } + h.fileNameToLastModTime[fileName] = currentModTime + return currentModTime, true +} + +func (h *FSEventHandler) UpsertHash(fileName string, hash [sha256.Size]byte) (updated bool) { + h.hashesMutex.Lock() + defer h.hashesMutex.Unlock() + lastHash := h.hashes[fileName] + if lastHash == hash { + return false + } + h.hashes[fileName] = hash + return true +} + +// generate Go code for a single template. +// If a basePath is provided, the filename included in error messages is relative to it. +func (h *FSEventHandler) generate(ctx context.Context, fileName string) (result GenerateResult, diagnostics []parser.Diagnostic, err error) { + t, err := parser.Parse(fileName) + if err != nil { + return GenerateResult{}, nil, fmt.Errorf("%s parsing error: %w", fileName, err) + } + targetFileName := strings.TrimSuffix(fileName, ".templ") + "_templ.go" + + // Only use relative filenames to the basepath for filenames in runtime error messages. + absFilePath, err := filepath.Abs(fileName) + if err != nil { + return GenerateResult{}, nil, fmt.Errorf("failed to get absolute path for %q: %w", fileName, err) + } + relFilePath, err := filepath.Rel(h.dir, absFilePath) + if err != nil { + return GenerateResult{}, nil, fmt.Errorf("failed to get relative path for %q: %w", fileName, err) + } + // Convert Windows file paths to Unix-style for consistency. + relFilePath = filepath.ToSlash(relFilePath) + + var b bytes.Buffer + generatorOutput, err := generator.Generate(t, &b, append(h.genOpts, generator.WithFileName(relFilePath))...) + if err != nil { + return GenerateResult{}, nil, fmt.Errorf("%s generation error: %w", fileName, err) + } + + formattedGoCode, err := format.Source(b.Bytes()) + if err != nil { + err = remapErrorList(err, generatorOutput.SourceMap, fileName) + return GenerateResult{}, nil, fmt.Errorf("%s source formatting error %w", fileName, err) + } + + // Hash output, and write out the file if the goCodeHash has changed. + goCodeHash := sha256.Sum256(formattedGoCode) + if h.UpsertHash(targetFileName, goCodeHash) { + result.Updated = true + if err = h.writer(targetFileName, formattedGoCode); err != nil { + return result, nil, fmt.Errorf("failed to write target file %q: %w", targetFileName, err) + } + } + + // Add the txt file if it has changed. + if h.devMode { + txtFileName := strings.TrimSuffix(fileName, ".templ") + "_templ.txt" + joined := strings.Join(generatorOutput.Literals, "\n") + txtHash := sha256.Sum256([]byte(joined)) + if h.UpsertHash(txtFileName, txtHash) { + result.TextUpdated = true + if err = os.WriteFile(txtFileName, []byte(joined), 0o644); err != nil { + return result, nil, fmt.Errorf("failed to write string literal file %q: %w", txtFileName, err) + } + } + + // Check whether the change would require a recompilation to take effect. + h.fileNameToOutputMutex.Lock() + defer h.fileNameToOutputMutex.Unlock() + previous := h.fileNameToOutput[fileName] + if generator.HasChanged(previous, generatorOutput) { + result.GoUpdated = true + } + h.fileNameToOutput[fileName] = generatorOutput + } + + parsedDiagnostics, err := parser.Diagnose(t) + if err != nil { + return result, nil, fmt.Errorf("%s diagnostics error: %w", fileName, err) + } + + if h.genSourceMapVis { + err = generateSourceMapVisualisation(ctx, fileName, targetFileName, generatorOutput.SourceMap) + } + + return result, parsedDiagnostics, err +} + +// Takes an error from the formatter and attempts to convert the positions reported in the target file to their positions +// in the source file. +func remapErrorList(err error, sourceMap *parser.SourceMap, fileName string) error { + list, ok := err.(scanner.ErrorList) + if !ok || len(list) == 0 { + return err + } + for i, e := range list { + // The positions in the source map are off by one line because of the package definition. + srcPos, ok := sourceMap.SourcePositionFromTarget(uint32(e.Pos.Line-1), uint32(e.Pos.Column)) + if !ok { + continue + } + list[i].Pos = token.Position{ + Filename: fileName, + Offset: int(srcPos.Index), + Line: int(srcPos.Line) + 1, + Column: int(srcPos.Col), + } + } + return list +} + +func generateSourceMapVisualisation(ctx context.Context, templFileName, goFileName string, sourceMap *parser.SourceMap) error { + if err := ctx.Err(); err != nil { + return err + } + var templContents, goContents []byte + var templErr, goErr error + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + templContents, templErr = os.ReadFile(templFileName) + }() + go func() { + defer wg.Done() + goContents, goErr = os.ReadFile(goFileName) + }() + wg.Wait() + if templErr != nil { + return templErr + } + if goErr != nil { + return templErr + } + + targetFileName := strings.TrimSuffix(templFileName, ".templ") + "_templ_sourcemap.html" + w, err := os.Create(targetFileName) + if err != nil { + return fmt.Errorf("%s sourcemap visualisation error: %w", templFileName, err) + } + defer w.Close() + b := bufio.NewWriter(w) + defer b.Flush() + + return visualize.HTML(templFileName, string(templContents), string(goContents), sourceMap).Render(ctx, b) +} diff --git a/templ/cmd/templ/generatecmd/fatalerror.go b/templ/cmd/templ/generatecmd/fatalerror.go new file mode 100644 index 0000000..1081659 --- /dev/null +++ b/templ/cmd/templ/generatecmd/fatalerror.go @@ -0,0 +1,23 @@ +package generatecmd + +type FatalError struct { + Err error +} + +func (e FatalError) Error() string { + return e.Err.Error() +} + +func (e FatalError) Unwrap() error { + return e.Err +} + +func (e FatalError) Is(target error) bool { + _, ok := target.(FatalError) + return ok +} + +func (e FatalError) As(target any) bool { + _, ok := target.(*FatalError) + return ok +} diff --git a/templ/cmd/templ/generatecmd/main.go b/templ/cmd/templ/generatecmd/main.go new file mode 100644 index 0000000..4d2cbf5 --- /dev/null +++ b/templ/cmd/templ/generatecmd/main.go @@ -0,0 +1,39 @@ +package generatecmd + +import ( + "context" + _ "embed" + "log/slog" + + _ "net/http/pprof" +) + +type Arguments struct { + FileName string + FileWriter FileWriterFunc + Path string + Watch bool + WatchPattern string + OpenBrowser bool + Command string + ProxyBind string + ProxyPort int + Proxy string + NotifyProxy bool + WorkerCount int + GenerateSourceMapVisualisations bool + IncludeVersion bool + IncludeTimestamp bool + // PPROFPort is the port to run the pprof server on. + PPROFPort int + KeepOrphanedFiles bool + Lazy bool +} + +func Run(ctx context.Context, log *slog.Logger, args Arguments) (err error) { + g, err := NewGenerate(log, args) + if err != nil { + return err + } + return g.Run(ctx) +} diff --git a/templ/cmd/templ/generatecmd/main_test.go b/templ/cmd/templ/generatecmd/main_test.go new file mode 100644 index 0000000..b13c8eb --- /dev/null +++ b/templ/cmd/templ/generatecmd/main_test.go @@ -0,0 +1,170 @@ +package generatecmd + +import ( + "context" + "io" + "log/slog" + "os" + "path" + "regexp" + "testing" + "time" + + "github.com/a-h/templ/cmd/templ/testproject" + "golang.org/x/sync/errgroup" +) + +func TestGenerate(t *testing.T) { + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + t.Run("can generate a file in place", func(t *testing.T) { + // templ generate -f templates.templ + dir, err := testproject.Create("github.com/a-h/templ/cmd/templ/testproject") + if err != nil { + t.Fatalf("failed to create test project: %v", err) + } + defer os.RemoveAll(dir) + + // Delete the templates_templ.go file to ensure it is generated. + err = os.Remove(path.Join(dir, "templates_templ.go")) + if err != nil { + t.Fatalf("failed to remove templates_templ.go: %v", err) + } + + // Run the generate command. + err = Run(context.Background(), log, Arguments{ + FileName: path.Join(dir, "templates.templ"), + }) + if err != nil { + t.Fatalf("failed to run generate command: %v", err) + } + + // Check the templates_templ.go file was created. + _, err = os.Stat(path.Join(dir, "templates_templ.go")) + if err != nil { + t.Fatalf("templates_templ.go was not created: %v", err) + } + }) + t.Run("can generate a file in watch mode", func(t *testing.T) { + // templ generate -f templates.templ + dir, err := testproject.Create("github.com/a-h/templ/cmd/templ/testproject") + if err != nil { + t.Fatalf("failed to create test project: %v", err) + } + defer os.RemoveAll(dir) + + // Delete the templates_templ.go file to ensure it is generated. + err = os.Remove(path.Join(dir, "templates_templ.go")) + if err != nil { + t.Fatalf("failed to remove templates_templ.go: %v", err) + } + ctx, cancel := context.WithCancel(context.Background()) + + var eg errgroup.Group + eg.Go(func() error { + // Run the generate command. + return Run(ctx, log, Arguments{ + Path: dir, + Watch: true, + }) + }) + + // Check the templates_templ.go file was created, with backoff. + for i := 0; i < 5; i++ { + time.Sleep(time.Second * time.Duration(i)) + _, err = os.Stat(path.Join(dir, "templates_templ.go")) + if err != nil { + continue + } + _, err = os.Stat(path.Join(dir, "templates_templ.txt")) + if err != nil { + continue + } + break + } + if err != nil { + t.Fatalf("template files were not created: %v", err) + } + + cancel() + if err := eg.Wait(); err != nil { + t.Fatalf("generate command failed: %v", err) + } + + // Check the templates_templ.txt file was removed. + _, err = os.Stat(path.Join(dir, "templates_templ.txt")) + if err == nil { + t.Fatalf("templates_templ.txt was not removed") + } + }) +} + +func TestDefaultWatchPattern(t *testing.T) { + tests := []struct { + name string + input string + matches bool + }{ + { + name: "empty file names do not match", + input: "", + matches: false, + }, + { + name: "*_templ.txt matches, Windows", + input: `C:\Users\adrian\github.com\a-h\templ\cmd\templ\testproject\strings_templ.txt`, + matches: true, + }, + { + name: "*_templ.txt matches, Unix", + input: "/Users/adrian/github.com/a-h/templ/cmd/templ/testproject/strings_templ.txt", + matches: true, + }, + { + name: "*.templ files match, Windows", + input: `C:\Users\adrian\github.com\a-h\templ\cmd\templ\testproject\templates.templ`, + matches: true, + }, + { + name: "*.templ files match, Unix", + input: "/Users/adrian/github.com/a-h/templ/cmd/templ/testproject/templates.templ", + matches: true, + }, + { + name: "*_templ.go files match, Windows", + input: `C:\Users\adrian\github.com\a-h\templ\cmd\templ\testproject\templates_templ.go`, + matches: true, + }, + { + name: "*_templ.go files match, Unix", + input: "/Users/adrian/github.com/a-h/templ/cmd/templ/testproject/templates_templ.go", + matches: true, + }, + { + name: "*.go files match, Windows", + input: `C:\Users\adrian\github.com\a-h\templ\cmd\templ\testproject\templates.go`, + matches: true, + }, + { + name: "*.go files match, Unix", + input: "/Users/adrian/github.com/a-h/templ/cmd/templ/testproject/templates.go", + matches: true, + }, + { + name: "*.css files do not match", + input: "/Users/adrian/github.com/a-h/templ/cmd/templ/testproject/templates.css", + matches: false, + }, + } + wpRegexp, err := regexp.Compile(defaultWatchPattern) + if err != nil { + t.Fatalf("failed to compile default watch pattern: %v", err) + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + if wpRegexp.MatchString(test.input) != test.matches { + t.Fatalf("expected match of %q to be %v", test.input, test.matches) + } + }) + } +} diff --git a/templ/cmd/templ/generatecmd/modcheck/modcheck.go b/templ/cmd/templ/generatecmd/modcheck/modcheck.go new file mode 100644 index 0000000..bc3fc03 --- /dev/null +++ b/templ/cmd/templ/generatecmd/modcheck/modcheck.go @@ -0,0 +1,82 @@ +package modcheck + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/a-h/templ" + "golang.org/x/mod/modfile" + "golang.org/x/mod/semver" +) + +// WalkUp the directory tree, starting at dir, until we find a directory containing +// a go.mod file. +func WalkUp(dir string) (string, error) { + dir, err := filepath.Abs(dir) + if err != nil { + return "", fmt.Errorf("failed to get absolute path: %w", err) + } + + var modFile string + for { + modFile = filepath.Join(dir, "go.mod") + _, err := os.Stat(modFile) + if err != nil && !os.IsNotExist(err) { + return "", fmt.Errorf("failed to stat go.mod file: %w", err) + } + if os.IsNotExist(err) { + // Move up. + prev := dir + dir = filepath.Dir(dir) + if dir == prev { + break + } + continue + } + break + } + + // No file found. + if modFile == "" { + return dir, fmt.Errorf("could not find go.mod file") + } + return dir, nil +} + +func Check(dir string) error { + dir, err := WalkUp(dir) + if err != nil { + return err + } + + // Found a go.mod file. + // Read it and find the templ version. + modFile := filepath.Join(dir, "go.mod") + m, err := os.ReadFile(modFile) + if err != nil { + return fmt.Errorf("failed to read go.mod file: %w", err) + } + + mf, err := modfile.Parse(modFile, m, nil) + if err != nil { + return fmt.Errorf("failed to parse go.mod file: %w", err) + } + if mf.Module.Mod.Path == "github.com/a-h/templ" { + // The go.mod file is for templ itself. + return nil + } + for _, r := range mf.Require { + if r.Mod.Path == "github.com/a-h/templ" { + cmp := semver.Compare(r.Mod.Version, templ.Version()) + if cmp < 0 { + return fmt.Errorf("generator %v is newer than templ version %v found in go.mod file, consider running `go get -u github.com/a-h/templ` to upgrade", templ.Version(), r.Mod.Version) + } + if cmp > 0 { + return fmt.Errorf("generator %v is older than templ version %v found in go.mod file, consider upgrading templ CLI", templ.Version(), r.Mod.Version) + } + return nil + } + } + return fmt.Errorf("templ not found in go.mod file, run `go get github.com/a-h/templ` to install it") +} diff --git a/templ/cmd/templ/generatecmd/modcheck/modcheck_test.go b/templ/cmd/templ/generatecmd/modcheck/modcheck_test.go new file mode 100644 index 0000000..544642b --- /dev/null +++ b/templ/cmd/templ/generatecmd/modcheck/modcheck_test.go @@ -0,0 +1,47 @@ +package modcheck + +import ( + "testing" + + "golang.org/x/mod/modfile" +) + +func TestPatchGoVersion(t *testing.T) { + tests := []struct { + input string + expected string + }{ + { + input: "go 1.20", + expected: "1.20", + }, + { + input: "go 1.20.123", + expected: "1.20.123", + }, + { + input: "go 1.20.1", + expected: "1.20.1", + }, + { + input: "go 1.20rc1", + expected: "1.20rc1", + }, + { + input: "go 1.15", + expected: "1.15", + }, + } + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + input := "module github.com/a-h/templ\n\n" + string(test.input) + "\n" + "toolchain go1.27.9\n" + mf, err := modfile.Parse("go.mod", []byte(input), nil) + if err != nil { + t.Fatalf("failed to parse go.mod: %v", err) + } + if test.expected != mf.Go.Version { + t.Errorf("expected %q, got %q", test.expected, mf.Go.Version) + } + }) + } +} diff --git a/templ/cmd/templ/generatecmd/proxy/proxy.go b/templ/cmd/templ/generatecmd/proxy/proxy.go new file mode 100644 index 0000000..f8d4ccd --- /dev/null +++ b/templ/cmd/templ/generatecmd/proxy/proxy.go @@ -0,0 +1,284 @@ +package proxy + +import ( + "bytes" + "compress/gzip" + "fmt" + "html" + "io" + stdlog "log" + "log/slog" + "math" + "net/http" + "net/http/httputil" + "net/url" + "os" + "strconv" + "strings" + "time" + + "github.com/PuerkitoBio/goquery" + "github.com/a-h/templ/cmd/templ/generatecmd/sse" + "github.com/andybalholm/brotli" + + _ "embed" +) + +//go:embed script.js +var script string + +type Handler struct { + log *slog.Logger + URL string + Target *url.URL + p *httputil.ReverseProxy + sse *sse.Handler +} + +func getScriptTag(nonce string) string { + if nonce != "" { + var sb strings.Builder + sb.WriteString(``) + return sb.String() + } + return `` +} + +func insertScriptTagIntoBody(nonce, body string) (updated string) { + doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) + if err != nil { + return strings.Replace(body, "", getScriptTag(nonce)+"", -1) + } + doc.Find("body").AppendHtml(getScriptTag(nonce)) + r, err := doc.Html() + if err != nil { + return strings.Replace(body, "", getScriptTag(nonce)+"", -1) + } + return r +} + +type passthroughWriteCloser struct { + io.Writer +} + +func (pwc passthroughWriteCloser) Close() error { + return nil +} + +const unsupportedContentEncoding = "Unsupported content encoding, hot reload script not inserted." + +func (h *Handler) modifyResponse(r *http.Response) error { + log := h.log.With(slog.String("url", r.Request.URL.String())) + if r.Header.Get("templ-skip-modify") == "true" { + log.Debug("Skipping response modification because templ-skip-modify header is set") + return nil + } + if contentType := r.Header.Get("Content-Type"); !strings.HasPrefix(contentType, "text/html") { + log.Debug("Skipping response modification because content type is not text/html", slog.String("content-type", contentType)) + return nil + } + + // Set up readers and writers. + newReader := func(in io.Reader) (out io.Reader, err error) { + return in, nil + } + newWriter := func(out io.Writer) io.WriteCloser { + return passthroughWriteCloser{out} + } + switch r.Header.Get("Content-Encoding") { + case "gzip": + newReader = func(in io.Reader) (out io.Reader, err error) { + return gzip.NewReader(in) + } + newWriter = func(out io.Writer) io.WriteCloser { + return gzip.NewWriter(out) + } + case "br": + newReader = func(in io.Reader) (out io.Reader, err error) { + return brotli.NewReader(in), nil + } + newWriter = func(out io.Writer) io.WriteCloser { + return brotli.NewWriter(out) + } + case "": + log.Debug("No content encoding header found") + default: + h.log.Warn(unsupportedContentEncoding, slog.String("encoding", r.Header.Get("Content-Encoding"))) + } + + // Read the encoded body. + encr, err := newReader(r.Body) + if err != nil { + return err + } + defer r.Body.Close() + body, err := io.ReadAll(encr) + if err != nil { + return err + } + + // Update it. + csp := r.Header.Get("Content-Security-Policy") + updated := insertScriptTagIntoBody(parseNonce(csp), string(body)) + if log.Enabled(r.Request.Context(), slog.LevelDebug) { + if len(updated) == len(body) { + log.Debug("Reload script not inserted") + } else { + log.Debug("Reload script inserted") + } + } + + // Encode the response. + var buf bytes.Buffer + encw := newWriter(&buf) + _, err = encw.Write([]byte(updated)) + if err != nil { + return err + } + err = encw.Close() + if err != nil { + return err + } + + // Update the response. + r.Body = io.NopCloser(&buf) + r.ContentLength = int64(buf.Len()) + r.Header.Set("Content-Length", strconv.Itoa(buf.Len())) + return nil +} + +func parseNonce(csp string) (nonce string) { +outer: + for _, rawDirective := range strings.Split(csp, ";") { + parts := strings.Fields(rawDirective) + if len(parts) < 2 { + continue + } + if parts[0] != "script-src" { + continue + } + for _, source := range parts[1:] { + source = strings.TrimPrefix(source, "'") + source = strings.TrimSuffix(source, "'") + if strings.HasPrefix(source, "nonce-") { + nonce = source[6:] + break outer + } + } + } + return nonce +} + +func New(log *slog.Logger, bind string, port int, target *url.URL) (h *Handler) { + p := httputil.NewSingleHostReverseProxy(target) + p.ErrorLog = stdlog.New(os.Stderr, "Proxy to target error: ", 0) + p.Transport = &roundTripper{ + maxRetries: 20, + initialDelay: 100 * time.Millisecond, + backoffExponent: 1.5, + } + h = &Handler{ + log: log, + URL: fmt.Sprintf("http://%s:%d", bind, port), + Target: target, + p: p, + sse: sse.New(), + } + p.ModifyResponse = h.modifyResponse + return h +} + +func (p *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/_templ/reload/script.js" { + // Provides a script that reloads the page. + w.Header().Add("Content-Type", "text/javascript") + _, err := io.WriteString(w, script) + if err != nil { + fmt.Printf("failed to write script: %v\n", err) + } + return + } + if r.URL.Path == "/_templ/reload/events" { + switch r.Method { + case http.MethodGet: + // Provides a list of messages including a reload message. + p.sse.ServeHTTP(w, r) + return + case http.MethodPost: + // Send a reload message to all connected clients. + p.sse.Send("message", "reload") + return + } + http.Error(w, "only GET or POST method allowed", http.StatusMethodNotAllowed) + return + } + p.p.ServeHTTP(w, r) +} + +func (p *Handler) SendSSE(eventType string, data string) { + p.sse.Send(eventType, data) +} + +type roundTripper struct { + maxRetries int + initialDelay time.Duration + backoffExponent float64 +} + +func (rt *roundTripper) setShouldSkipResponseModificationHeader(r *http.Request, resp *http.Response) { + // Instruct the modifyResponse function to skip modifying the response if the + // HTTP request has come from HTMX. + if r.Header.Get("HX-Request") != "true" { + return + } + resp.Header.Set("templ-skip-modify", "true") +} + +func (rt *roundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + // Read and buffer the body. + var bodyBytes []byte + if r.Body != nil && r.Body != http.NoBody { + var err error + bodyBytes, err = io.ReadAll(r.Body) + if err != nil { + return nil, err + } + r.Body.Close() + } + + // Retry logic. + var resp *http.Response + var err error + for retries := 0; retries < rt.maxRetries; retries++ { + // Clone the request and set the body. + req := r.Clone(r.Context()) + if bodyBytes != nil { + req.Body = io.NopCloser(bytes.NewReader(bodyBytes)) + } + + // Execute the request. + resp, err = http.DefaultTransport.RoundTrip(req) + if err != nil { + time.Sleep(rt.initialDelay * time.Duration(math.Pow(rt.backoffExponent, float64(retries)))) + continue + } + + rt.setShouldSkipResponseModificationHeader(r, resp) + + return resp, nil + } + + return nil, fmt.Errorf("max retries reached: %q", r.URL.String()) +} + +func NotifyProxy(host string, port int) error { + urlStr := fmt.Sprintf("http://%s:%d/_templ/reload/events", host, port) + req, err := http.NewRequest(http.MethodPost, urlStr, nil) + if err != nil { + return err + } + _, err = http.DefaultClient.Do(req) + return err +} diff --git a/templ/cmd/templ/generatecmd/proxy/proxy_test.go b/templ/cmd/templ/generatecmd/proxy/proxy_test.go new file mode 100644 index 0000000..48123c4 --- /dev/null +++ b/templ/cmd/templ/generatecmd/proxy/proxy_test.go @@ -0,0 +1,627 @@ +package proxy + +import ( + "bufio" + "bytes" + "compress/gzip" + "context" + "fmt" + "io" + "log/slog" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "sync" + "testing" + "time" + + "github.com/andybalholm/brotli" + "github.com/google/go-cmp/cmp" +) + +func TestRoundTripper(t *testing.T) { + t.Run("if the HX-Request header is present, set the templ-skip-modify header on the response", func(t *testing.T) { + rt := &roundTripper{} + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf("unexpected error creating request: %v", err) + } + req.Header.Set("HX-Request", "true") + resp := &http.Response{Header: make(http.Header)} + rt.setShouldSkipResponseModificationHeader(req, resp) + if resp.Header.Get("templ-skip-modify") != "true" { + t.Errorf("expected templ-skip-modify header to be true, got %v", resp.Header.Get("templ-skip-modify")) + } + }) + t.Run("if the HX-Request header is not present, do not set the templ-skip-modify header on the response", func(t *testing.T) { + rt := &roundTripper{} + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatalf("unexpected error creating request: %v", err) + } + resp := &http.Response{Header: make(http.Header)} + rt.setShouldSkipResponseModificationHeader(req, resp) + if resp.Header.Get("templ-skip-modify") != "" { + t.Errorf("expected templ-skip-modify header to be empty, got %v", resp.Header.Get("templ-skip-modify")) + } + }) +} + +func TestProxy(t *testing.T) { + t.Run("plain: non-html content is not modified", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(`{"key": "value"}`)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "application/json") + r.Header.Set("Content-Length", "16") + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != "16" { + t.Errorf("expected content length to be 16, got %v", r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(`{"key": "value"}`, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("plain: if the response contains templ-skip-modify header, it is not modified", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(`Hello`)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html") + r.Header.Set("Content-Length", "5") + r.Header.Set("templ-skip-modify", "true") + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != "5" { + t.Errorf("expected content length to be 5, got %v", r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(`Hello`, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("plain: body tags get the script inserted", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(``)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Length", "26") + + expectedString := insertScriptTagIntoBody("", ``) + if !strings.Contains(expectedString, getScriptTag("")) { + t.Fatalf("expected the script tag to be inserted, but it wasn't: %q", expectedString) + } + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != fmt.Sprintf("%d", len(expectedString)) { + t.Errorf("expected content length to be %d, got %v", len(expectedString), r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(expectedString, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("plain: body tags get the script inserted with nonce", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(``)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Length", "26") + const nonce = "this-is-the-nonce" + r.Header.Set("Content-Security-Policy", fmt.Sprintf("script-src 'nonce-%s'", nonce)) + + expectedString := insertScriptTagIntoBody(nonce, ``) + if !strings.Contains(expectedString, getScriptTag(nonce)) { + t.Fatalf("expected the script tag to be inserted, but it wasn't: %q", expectedString) + } + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != fmt.Sprintf("%d", len(expectedString)) { + t.Errorf("expected content length to be %d, got %v", len(expectedString), r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(expectedString, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("plain: body tags get the script inserted ignoring js with body tags", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(``)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Length", "26") + + expectedString := insertScriptTagIntoBody("", ``) + if !strings.Contains(expectedString, getScriptTag("")) { + t.Fatalf("expected the script tag to be inserted, but it wasn't: %q", expectedString) + } + if !strings.Contains(expectedString, `console.log("")`) { + t.Fatalf("expected the script tag to be inserted, but mangled the html: %q", expectedString) + } + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != fmt.Sprintf("%d", len(expectedString)) { + t.Errorf("expected content length to be %d, got %v", len(expectedString), r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(expectedString, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("gzip: non-html content is not modified", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(strings.NewReader(`{"key": "value"}`)), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "application/json") + // It's not actually gzipped here, but it doesn't matter, it shouldn't get that far. + r.Header.Set("Content-Encoding", "gzip") + // Similarly, this is not the actual length of the gzipped content. + r.Header.Set("Content-Length", "16") + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != "16" { + t.Errorf("expected content length to be 16, got %v", r.Header.Get("Content-Length")) + } + actualBody, err := io.ReadAll(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(`{"key": "value"}`, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("gzip: body tags get the script inserted", func(t *testing.T) { + // Arrange + body := `` + var buf bytes.Buffer + gzw := gzip.NewWriter(&buf) + _, err := gzw.Write([]byte(body)) + if err != nil { + t.Fatalf("unexpected error writing gzip: %v", err) + } + gzw.Close() + + expectedString := insertScriptTagIntoBody("", body) + + var expectedBytes bytes.Buffer + gzw = gzip.NewWriter(&expectedBytes) + _, err = gzw.Write([]byte(expectedString)) + if err != nil { + t.Fatalf("unexpected error writing gzip: %v", err) + } + gzw.Close() + expectedLength := len(expectedBytes.Bytes()) + + r := &http.Response{ + Body: io.NopCloser(&buf), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Encoding", "gzip") + r.Header.Set("Content-Length", fmt.Sprintf("%d", expectedLength)) + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err = h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != fmt.Sprintf("%d", expectedLength) { + t.Errorf("expected content length to be %d, got %v", expectedLength, r.Header.Get("Content-Length")) + } + + gr, err := gzip.NewReader(r.Body) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + actualBody, err := io.ReadAll(gr) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(expectedString, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("brotli: body tags get the script inserted", func(t *testing.T) { + // Arrange + body := `` + var buf bytes.Buffer + brw := brotli.NewWriter(&buf) + _, err := brw.Write([]byte(body)) + if err != nil { + t.Fatalf("unexpected error writing gzip: %v", err) + } + brw.Close() + + expectedString := insertScriptTagIntoBody("", body) + + var expectedBytes bytes.Buffer + brw = brotli.NewWriter(&expectedBytes) + _, err = brw.Write([]byte(expectedString)) + if err != nil { + t.Fatalf("unexpected error writing gzip: %v", err) + } + brw.Close() + expectedLength := len(expectedBytes.Bytes()) + + r := &http.Response{ + Body: io.NopCloser(&buf), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Encoding", "br") + r.Header.Set("Content-Length", fmt.Sprintf("%d", expectedLength)) + + // Act + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err = h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if r.Header.Get("Content-Length") != fmt.Sprintf("%d", expectedLength) { + t.Errorf("expected content length to be %d, got %v", expectedLength, r.Header.Get("Content-Length")) + } + + actualBody, err := io.ReadAll(brotli.NewReader(r.Body)) + if err != nil { + t.Fatalf("unexpected error reading response: %v", err) + } + if diff := cmp.Diff(expectedString, string(actualBody)); diff != "" { + t.Errorf("unexpected response body (-got +want):\n%s", diff) + } + }) + t.Run("notify-proxy: sending POST request to /_templ/reload/events should receive reload sse event", func(t *testing.T) { + // Arrange 1: create a test proxy server. + dummyHandler := func(w http.ResponseWriter, r *http.Request) {} + dummyServer := httptest.NewServer(http.HandlerFunc(dummyHandler)) + defer dummyServer.Close() + + u, err := url.Parse(dummyServer.URL) + if err != nil { + t.Fatalf("unexpected error parsing URL: %v", err) + } + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + handler := New(log, "0.0.0.0", 0, u) + proxyServer := httptest.NewServer(handler) + defer proxyServer.Close() + + u2, err := url.Parse(proxyServer.URL) + if err != nil { + t.Fatalf("unexpected error parsing URL: %v", err) + } + port, err := strconv.Atoi(u2.Port()) + if err != nil { + t.Fatalf("unexpected error parsing port: %v", err) + } + + // Arrange 2: start a goroutine to listen for sse events. + ctx := context.Background() + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + errChan := make(chan error) + sseRespCh := make(chan string) + sseListening := make(chan bool) // Coordination channel that ensures the SSE listener is started before notifying the proxy. + go func() { + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/_templ/reload/events", proxyServer.URL), nil) + if err != nil { + errChan <- err + return + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + errChan <- err + return + } + defer resp.Body.Close() + + sseListening <- true + lines := []string{} + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + if scanner.Text() == "data: reload" { + sseRespCh <- strings.Join(lines, "\n") + return + } + } + err = scanner.Err() + if err != nil { + errChan <- err + return + } + }() + + // Act: notify the proxy. + select { // Either SSE is listening or an error occurred. + case <-sseListening: + err = NotifyProxy(u2.Hostname(), port) + if err != nil { + t.Fatalf("unexpected error notifying proxy: %v", err) + } + case err := <-errChan: + if err == nil { + t.Fatalf("unexpected sse response: %v", err) + } + } + + // Assert. + select { // Either SSE has a expected response or an error or timeout occurred. + case resp := <-sseRespCh: + if !strings.Contains(resp, "event: message\ndata: reload") { + t.Errorf("expected sse reload event to be received, got: %q", resp) + } + case err := <-errChan: + if err == nil { + t.Fatalf("unexpected sse response: %v", err) + } + case <-ctx.Done(): + t.Fatalf("timeout waiting for sse response") + } + }) + t.Run("unsupported encodings result in a warning", func(t *testing.T) { + // Arrange + r := &http.Response{ + Body: io.NopCloser(bytes.NewReader([]byte("

Data

"))), + Header: make(http.Header), + Request: &http.Request{ + URL: &url.URL{ + Scheme: "http", + Host: "example.com", + }, + }, + } + r.Header.Set("Content-Type", "text/html, charset=utf-8") + r.Header.Set("Content-Encoding", "weird-encoding") + + // Act + lh := newTestLogHandler(slog.LevelInfo) + log := slog.New(lh) + h := New(log, "127.0.0.1", 7474, &url.URL{Scheme: "http", Host: "example.com"}) + err := h.modifyResponse(r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Assert + if len(lh.records) != 1 { + var sb strings.Builder + for _, record := range lh.records { + sb.WriteString(record.Message) + sb.WriteString("\n") + } + t.Fatalf("expected 1 log entry, but got %d: \n%s", len(lh.records), sb.String()) + } + record := lh.records[0] + if record.Message != unsupportedContentEncoding { + t.Errorf("expected warning message %q, got %q", unsupportedContentEncoding, record.Message) + } + if record.Level != slog.LevelWarn { + t.Errorf("expected warning, got level %v", record.Level) + } + }) +} + +func newTestLogHandler(level slog.Level) *testLogHandler { + return &testLogHandler{ + m: new(sync.Mutex), + records: nil, + level: level, + } +} + +type testLogHandler struct { + m *sync.Mutex + records []slog.Record + level slog.Level +} + +func (h *testLogHandler) Enabled(ctx context.Context, l slog.Level) bool { + return l >= h.level +} + +func (h *testLogHandler) Handle(ctx context.Context, r slog.Record) error { + h.m.Lock() + defer h.m.Unlock() + if r.Level < h.level { + return nil + } + h.records = append(h.records, r) + return nil +} + +func (h *testLogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return h +} + +func (h *testLogHandler) WithGroup(name string) slog.Handler { + return h +} + +func TestParseNonce(t *testing.T) { + for _, tc := range []struct { + name string + csp string + expected string + }{ + { + name: "empty csp", + csp: "", + expected: "", + }, + { + name: "simple csp", + csp: "script-src 'nonce-oLhVst3hTAcxI734qtB0J9Qc7W4qy09C'", + expected: "oLhVst3hTAcxI734qtB0J9Qc7W4qy09C", + }, + { + name: "simple csp without single quote", + csp: "script-src nonce-oLhVst3hTAcxI734qtB0J9Qc7W4qy09C", + expected: "oLhVst3hTAcxI734qtB0J9Qc7W4qy09C", + }, + { + name: "complete csp", + csp: "default-src 'self'; frame-ancestors 'self'; form-action 'self'; script-src 'strict-dynamic' 'nonce-4VOtk0Uo1l7pwtC';", + expected: "4VOtk0Uo1l7pwtC", + }, + { + name: "mdn example 1", + csp: "default-src 'self'", + expected: "", + }, + { + name: "mdn example 2", + csp: "default-src 'self' *.trusted.com", + expected: "", + }, + { + name: "mdn example 3", + csp: "default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com", + expected: "", + }, + { + name: "mdn example 3 multiple sources", + csp: "default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com foo.com 'strict-dynamic' 'nonce-4VOtk0Uo1l7pwtC'", + expected: "4VOtk0Uo1l7pwtC", + }, + } { + t.Run(tc.name, func(t *testing.T) { + nonce := parseNonce(tc.csp) + if nonce != tc.expected { + t.Errorf("expected nonce to be %s, but got %s", tc.expected, nonce) + } + }) + } +} diff --git a/templ/cmd/templ/generatecmd/proxy/script.js b/templ/cmd/templ/generatecmd/proxy/script.js new file mode 100644 index 0000000..8e55791 --- /dev/null +++ b/templ/cmd/templ/generatecmd/proxy/script.js @@ -0,0 +1,10 @@ +(function() { + let templ_reloadSrc = window.templ_reloadSrc || new EventSource("/_templ/reload/events"); + templ_reloadSrc.onmessage = (event) => { + if (event && event.data === "reload") { + window.location.reload(); + } + }; + window.templ_reloadSrc = templ_reloadSrc; + window.onbeforeunload = () => window.templ_reloadSrc.close(); +})(); diff --git a/templ/cmd/templ/generatecmd/run/run_test.go b/templ/cmd/templ/generatecmd/run/run_test.go new file mode 100644 index 0000000..a1a0cff --- /dev/null +++ b/templ/cmd/templ/generatecmd/run/run_test.go @@ -0,0 +1,108 @@ +package run_test + +import ( + "context" + "embed" + "io" + "net/http" + "os" + "path/filepath" + "syscall" + "testing" + "time" + + "github.com/a-h/templ/cmd/templ/generatecmd/run" +) + +//go:embed testprogram/* +var testprogram embed.FS + +func TestGoRun(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + // Copy testprogram to a temporary directory. + dir, err := os.MkdirTemp("", "testprogram") + if err != nil { + t.Fatalf("failed to make test dir: %v", err) + } + files, err := testprogram.ReadDir("testprogram") + if err != nil { + t.Fatalf("failed to read embedded dir: %v", err) + } + for _, file := range files { + srcFileName := "testprogram/" + file.Name() + srcData, err := testprogram.ReadFile(srcFileName) + if err != nil { + t.Fatalf("failed to read src file %q: %v", srcFileName, err) + } + tgtFileName := filepath.Join(dir, file.Name()) + tgtFile, err := os.Create(tgtFileName) + if err != nil { + t.Fatalf("failed to create tgt file %q: %v", tgtFileName, err) + } + defer tgtFile.Close() + if _, err := tgtFile.Write(srcData); err != nil { + t.Fatalf("failed to write to tgt file %q: %v", tgtFileName, err) + } + } + // Rename the go.mod.embed file to go.mod. + if err := os.Rename(filepath.Join(dir, "go.mod.embed"), filepath.Join(dir, "go.mod")); err != nil { + t.Fatalf("failed to rename go.mod.embed: %v", err) + } + + tests := []struct { + name string + cmd string + }{ + { + name: "Well behaved programs get shut down", + cmd: "go run .", + }, + { + name: "Badly behaved programs get shut down", + cmd: "go run . -badly-behaved", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + cmd, err := run.Run(ctx, dir, tt.cmd) + if err != nil { + t.Fatalf("failed to run program: %v", err) + } + + time.Sleep(1 * time.Second) + + pid := cmd.Process.Pid + + if err := run.KillAll(); err != nil { + t.Fatalf("failed to kill all: %v", err) + } + + // Check the parent process is no longer running. + if err := cmd.Process.Signal(os.Signal(syscall.Signal(0))); err == nil { + t.Fatalf("process %d is still running", pid) + } + // Check that the child was stopped. + body, err := readResponse("http://localhost:7777") + if err == nil { + t.Fatalf("child process is still running: %s", body) + } + }) + } +} + +func readResponse(url string) (body string, err error) { + resp, err := http.Get(url) + if err != nil { + return body, err + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err != nil { + return body, err + } + return string(b), nil +} diff --git a/templ/cmd/templ/generatecmd/run/run_unix.go b/templ/cmd/templ/generatecmd/run/run_unix.go new file mode 100644 index 0000000..f2f4bfb --- /dev/null +++ b/templ/cmd/templ/generatecmd/run/run_unix.go @@ -0,0 +1,84 @@ +//go:build unix + +package run + +import ( + "context" + "errors" + "fmt" + "os" + "os/exec" + "strings" + "sync" + "syscall" + "time" +) + +var ( + m = &sync.Mutex{} + running = map[string]*exec.Cmd{} +) + +func KillAll() (err error) { + m.Lock() + defer m.Unlock() + var errs []error + for _, cmd := range running { + if err := kill(cmd); err != nil { + errs = append(errs, fmt.Errorf("failed to kill process %d: %w", cmd.Process.Pid, err)) + } + } + running = map[string]*exec.Cmd{} + return errors.Join(errs...) +} + +func kill(cmd *exec.Cmd) (err error) { + errs := make([]error, 4) + errs[0] = ignoreExited(cmd.Process.Signal(syscall.SIGINT)) + errs[1] = ignoreExited(cmd.Process.Signal(syscall.SIGTERM)) + errs[2] = ignoreExited(cmd.Wait()) + errs[3] = ignoreExited(syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)) + return errors.Join(errs...) +} + +func ignoreExited(err error) error { + if errors.Is(err, syscall.ESRCH) { + return nil + } + // Ignore *exec.ExitError + if _, ok := err.(*exec.ExitError); ok { + return nil + } + return err +} + +func Run(ctx context.Context, workingDir string, input string) (cmd *exec.Cmd, err error) { + m.Lock() + defer m.Unlock() + cmd, ok := running[input] + if ok { + if err := kill(cmd); err != nil { + return cmd, fmt.Errorf("failed to kill process %d: %w", cmd.Process.Pid, err) + } + + delete(running, input) + } + parts := strings.Fields(input) + executable := parts[0] + args := []string{} + if len(parts) > 1 { + args = append(args, parts[1:]...) + } + + cmd = exec.CommandContext(ctx, executable, args...) + // Wait for the process to finish gracefully before termination. + cmd.WaitDelay = time.Second * 3 + cmd.Env = os.Environ() + cmd.Dir = workingDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + running[input] = cmd + err = cmd.Start() + return +} diff --git a/templ/cmd/templ/generatecmd/run/run_windows.go b/templ/cmd/templ/generatecmd/run/run_windows.go new file mode 100644 index 0000000..0a79032 --- /dev/null +++ b/templ/cmd/templ/generatecmd/run/run_windows.go @@ -0,0 +1,69 @@ +//go:build windows + +package run + +import ( + "context" + "os" + "os/exec" + "strconv" + "strings" + "sync" +) + +var m = &sync.Mutex{} +var running = map[string]*exec.Cmd{} + +func KillAll() (err error) { + m.Lock() + defer m.Unlock() + for _, cmd := range running { + kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)) + kill.Stderr = os.Stderr + kill.Stdout = os.Stdout + err := kill.Run() + if err != nil { + return err + } + } + running = map[string]*exec.Cmd{} + return +} + +func Stop(cmd *exec.Cmd) (err error) { + kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)) + kill.Stderr = os.Stderr + kill.Stdout = os.Stdout + return kill.Run() +} + +func Run(ctx context.Context, workingDir string, input string) (cmd *exec.Cmd, err error) { + m.Lock() + defer m.Unlock() + cmd, ok := running[input] + if ok { + kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid)) + kill.Stderr = os.Stderr + kill.Stdout = os.Stdout + err := kill.Run() + if err != nil { + return cmd, err + } + delete(running, input) + } + parts := strings.Fields(input) + executable := parts[0] + args := []string{} + if len(parts) > 1 { + args = append(args, parts[1:]...) + } + + cmd = exec.Command(executable, args...) + cmd.Env = os.Environ() + cmd.Dir = workingDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + running[input] = cmd + err = cmd.Start() + return +} diff --git a/templ/cmd/templ/generatecmd/run/testprogram/go.mod.embed b/templ/cmd/templ/generatecmd/run/testprogram/go.mod.embed new file mode 100644 index 0000000..157fcea --- /dev/null +++ b/templ/cmd/templ/generatecmd/run/testprogram/go.mod.embed @@ -0,0 +1,3 @@ +module testprogram + +go 1.23 diff --git a/templ/cmd/templ/generatecmd/run/testprogram/main.go b/templ/cmd/templ/generatecmd/run/testprogram/main.go new file mode 100644 index 0000000..04ef881 --- /dev/null +++ b/templ/cmd/templ/generatecmd/run/testprogram/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +// This is a test program. It is used only to test the behaviour of the run package. +// The run package is supposed to be able to run and stop programs. Those programs may start +// child processes, which should also be stopped when the parent program is stopped. + +// For example, running `go run .` will compile an executable and run it. + +// So, this program does nothing. It just waits for a signal to stop. + +// In "Well behaved" mode, the program will stop when it receives a signal. +// In "Badly behaved" mode, the program will ignore the signal and continue running. + +// The run package should be able to stop the program in both cases. + +var badlyBehavedFlag = flag.Bool("badly-behaved", false, "If set, the program will ignore the stop signal and continue running.") + +func main() { + flag.Parse() + + mode := "Well behaved" + if *badlyBehavedFlag { + mode = "Badly behaved" + } + fmt.Printf("%s process %d started.\n", mode, os.Getpid()) + + // Start a web server on a known port so that we can check that this process is + // not running, when it's been started as a child process, and we don't know + // its pid. + go func() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "%d", os.Getpid()) + }) + err := http.ListenAndServe("127.0.0.1:7777", nil) + if err != nil { + fmt.Printf("Error running web server: %v\n", err) + } + }() + + sigs := make(chan os.Signal, 1) + if !*badlyBehavedFlag { + signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) + } + for { + select { + case <-sigs: + fmt.Printf("Process %d received signal. Stopping.\n", os.Getpid()) + return + case <-time.After(1 * time.Second): + fmt.Printf("Process %d still running...\n", os.Getpid()) + } + } +} diff --git a/templ/cmd/templ/generatecmd/sse/server.go b/templ/cmd/templ/generatecmd/sse/server.go new file mode 100644 index 0000000..fb7fe92 --- /dev/null +++ b/templ/cmd/templ/generatecmd/sse/server.go @@ -0,0 +1,84 @@ +package sse + +import ( + _ "embed" + "fmt" + "net/http" + "sync" + "sync/atomic" + "time" +) + +func New() *Handler { + return &Handler{ + m: new(sync.Mutex), + requests: map[int64]chan event{}, + } +} + +type Handler struct { + m *sync.Mutex + counter int64 + requests map[int64]chan event +} + +type event struct { + Type string + Data string +} + +// Send an event to all connected clients. +func (s *Handler) Send(eventType string, data string) { + s.m.Lock() + defer s.m.Unlock() + for _, f := range s.requests { + f := f + go func(f chan event) { + f <- event{ + Type: eventType, + Data: data, + } + }(f) + } +} + +func (s *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + + id := atomic.AddInt64(&s.counter, 1) + s.m.Lock() + events := make(chan event) + s.requests[id] = events + s.m.Unlock() + defer func() { + s.m.Lock() + defer s.m.Unlock() + delete(s.requests, id) + close(events) + }() + + timer := time.NewTimer(0) +loop: + for { + select { + case <-timer.C: + if _, err := fmt.Fprintf(w, "event: message\ndata: ping\n\n"); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + timer.Reset(time.Second * 5) + case e := <-events: + if _, err := fmt.Fprintf(w, "event: %s\ndata: %s\n\n", e.Type, e.Data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + case <-r.Context().Done(): + break loop + } + w.(http.Flusher).Flush() + } +} diff --git a/templ/cmd/templ/generatecmd/symlink/symlink_test.go b/templ/cmd/templ/generatecmd/symlink/symlink_test.go new file mode 100644 index 0000000..eac5bc8 --- /dev/null +++ b/templ/cmd/templ/generatecmd/symlink/symlink_test.go @@ -0,0 +1,52 @@ +package symlink + +import ( + "context" + "io" + "log/slog" + "os" + "path" + "testing" + + "github.com/a-h/templ/cmd/templ/generatecmd" + "github.com/a-h/templ/cmd/templ/testproject" +) + +func TestSymlink(t *testing.T) { + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + t.Run("can generate if root is symlink", func(t *testing.T) { + // templ generate -f templates.templ + dir, err := testproject.Create("github.com/a-h/templ/cmd/templ/testproject") + if err != nil { + t.Fatalf("failed to create test project: %v", err) + } + defer os.RemoveAll(dir) + + symlinkPath := dir + "-symlink" + err = os.Symlink(dir, symlinkPath) + if err != nil { + t.Fatalf("failed to create dir symlink: %v", err) + } + defer os.Remove(symlinkPath) + + // Delete the templates_templ.go file to ensure it is generated. + err = os.Remove(path.Join(symlinkPath, "templates_templ.go")) + if err != nil { + t.Fatalf("failed to remove templates_templ.go: %v", err) + } + + // Run the generate command. + err = generatecmd.Run(context.Background(), log, generatecmd.Arguments{ + Path: symlinkPath, + }) + if err != nil { + t.Fatalf("failed to run generate command: %v", err) + } + + // Check the templates_templ.go file was created. + _, err = os.Stat(path.Join(symlinkPath, "templates_templ.go")) + if err != nil { + t.Fatalf("templates_templ.go was not created: %v", err) + } + }) +} diff --git a/templ/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go b/templ/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go new file mode 100644 index 0000000..8c13199 --- /dev/null +++ b/templ/cmd/templ/generatecmd/test-eventhandler/eventhandler_test.go @@ -0,0 +1,101 @@ +package testeventhandler + +import ( + "context" + "errors" + "fmt" + "go/scanner" + "go/token" + "io" + "log/slog" + "os" + "testing" + + "github.com/a-h/templ/cmd/templ/generatecmd" + "github.com/a-h/templ/generator" + "github.com/fsnotify/fsnotify" + "github.com/google/go-cmp/cmp" +) + +func TestErrorLocationMapping(t *testing.T) { + tests := []struct { + name string + rawFileName string + errorPositions []token.Position + }{ + { + name: "single error outputs location in srcFile", + rawFileName: "single_error.templ.error", + errorPositions: []token.Position{ + {Offset: 46, Line: 3, Column: 20}, + }, + }, + { + name: "multiple errors all output locations in srcFile", + rawFileName: "multiple_errors.templ.error", + errorPositions: []token.Position{ + {Offset: 41, Line: 3, Column: 15}, + {Offset: 101, Line: 7, Column: 22}, + {Offset: 126, Line: 10, Column: 1}, + }, + }, + } + + slog := slog.New(slog.NewTextHandler(io.Discard, &slog.HandlerOptions{})) + var fw generatecmd.FileWriterFunc + fseh := generatecmd.NewFSEventHandler(slog, ".", false, []generator.GenerateOpt{}, false, false, fw, false) + for _, test := range tests { + // The raw files cannot end in .templ because they will cause the generator to fail. Instead, + // we create a tmp file that ends in .templ only for the duration of the test. + rawFile, err := os.Open(test.rawFileName) + if err != nil { + t.Errorf("%s: Failed to open file %s: %v", test.name, test.rawFileName, err) + break + } + file, err := os.CreateTemp("", fmt.Sprintf("*%s.templ", test.rawFileName)) + if err != nil { + t.Errorf("%s: Failed to create a tmp file at %s: %v", test.name, file.Name(), err) + break + } + defer os.Remove(file.Name()) + if _, err = io.Copy(file, rawFile); err != nil { + t.Errorf("%s: Failed to copy contents from raw file %s to tmp %s: %v", test.name, test.rawFileName, file.Name(), err) + } + + event := fsnotify.Event{Name: file.Name(), Op: fsnotify.Write} + _, err = fseh.HandleEvent(context.Background(), event) + if err == nil { + t.Errorf("%s: no error was thrown", test.name) + break + } + list, ok := err.(scanner.ErrorList) + for !ok { + err = errors.Unwrap(err) + if err == nil { + t.Errorf("%s: reached end of error wrapping before finding an ErrorList", test.name) + break + } else { + list, ok = err.(scanner.ErrorList) + } + } + if !ok { + break + } + + if len(list) != len(test.errorPositions) { + t.Errorf("%s: expected %d errors but got %d", test.name, len(test.errorPositions), len(list)) + break + } + for i, err := range list { + test.errorPositions[i].Filename = file.Name() + diff := cmp.Diff(test.errorPositions[i], err.Pos) + if diff != "" { + t.Error(diff) + t.Error("expected:") + t.Error(test.errorPositions[i]) + t.Error("actual:") + t.Error(err.Pos) + } + } + } +} diff --git a/templ/cmd/templ/generatecmd/test-eventhandler/multiple_errors.templ.error b/templ/cmd/templ/generatecmd/test-eventhandler/multiple_errors.templ.error new file mode 100644 index 0000000..14f0c41 --- /dev/null +++ b/templ/cmd/templ/generatecmd/test-eventhandler/multiple_errors.templ.error @@ -0,0 +1,10 @@ +package testeventhandler + +func invalid(a: string) string { + return "foo" +} + +templ multipleError(a: string) { +
+} +l diff --git a/templ/cmd/templ/generatecmd/test-eventhandler/single_error.templ.error b/templ/cmd/templ/generatecmd/test-eventhandler/single_error.templ.error new file mode 100644 index 0000000..05c9e52 --- /dev/null +++ b/templ/cmd/templ/generatecmd/test-eventhandler/single_error.templ.error @@ -0,0 +1,5 @@ +package testeventhandler + +templ singleError(a: string) { +
+} diff --git a/templ/cmd/templ/generatecmd/testwatch/generate_test.go b/templ/cmd/templ/generatecmd/testwatch/generate_test.go new file mode 100644 index 0000000..70f4bd5 --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/generate_test.go @@ -0,0 +1,485 @@ +package testwatch + +import ( + "bufio" + "bytes" + "context" + "embed" + "fmt" + "io" + "log/slog" + "net" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "testing" + "time" + + "github.com/PuerkitoBio/goquery" + "github.com/a-h/templ/cmd/templ/generatecmd" + "github.com/a-h/templ/cmd/templ/generatecmd/modcheck" +) + +//go:embed testdata/* +var testdata embed.FS + +func createTestProject(moduleRoot string) (dir string, err error) { + dir, err = os.MkdirTemp("", "templ_watch_test_*") + if err != nil { + return dir, fmt.Errorf("failed to make test dir: %w", err) + } + files, err := testdata.ReadDir("testdata") + if err != nil { + return dir, fmt.Errorf("failed to read embedded dir: %w", err) + } + for _, file := range files { + src := filepath.Join("testdata", file.Name()) + data, err := testdata.ReadFile(src) + if err != nil { + return dir, fmt.Errorf("failed to read file: %w", err) + } + + target := filepath.Join(dir, file.Name()) + if file.Name() == "go.mod.embed" { + data = bytes.ReplaceAll(data, []byte("{moduleRoot}"), []byte(moduleRoot)) + target = filepath.Join(dir, "go.mod") + } + err = os.WriteFile(target, data, 0660) + if err != nil { + return dir, fmt.Errorf("failed to copy file: %w", err) + } + } + return dir, nil +} + +func replaceInFile(name, src, tgt string) error { + data, err := os.ReadFile(name) + if err != nil { + return err + } + updated := strings.Replace(string(data), src, tgt, -1) + return os.WriteFile(name, []byte(updated), 0660) +} + +func getPort() (port int, err error) { + var a *net.TCPAddr + if a, err = net.ResolveTCPAddr("tcp", "localhost:0"); err == nil { + var l *net.TCPListener + if l, err = net.ListenTCP("tcp", a); err == nil { + defer l.Close() + return l.Addr().(*net.TCPAddr).Port, nil + } + } + return +} + +func getHTML(url string) (doc *goquery.Document, err error) { + resp, err := http.Get(url) + if err != nil { + return nil, fmt.Errorf("failed to get %q: %w", url, err) + } + return goquery.NewDocumentFromReader(resp.Body) +} + +func TestCanAccessDirect(t *testing.T) { + if testing.Short() { + return + } + args, teardown, err := Setup(false) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + + // Assert. + doc, err := getHTML(args.AppURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + countText := doc.Find(`div[data-testid="count"]`).Text() + actualCount, err := strconv.Atoi(countText) + if err != nil { + t.Fatalf("got count %q instead of integer", countText) + } + if actualCount < 1 { + t.Errorf("expected count >= 1, got %d", actualCount) + } +} + +func TestCanAccessViaProxy(t *testing.T) { + if testing.Short() { + return + } + args, teardown, err := Setup(false) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + + // Assert. + doc, err := getHTML(args.ProxyURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + countText := doc.Find(`div[data-testid="count"]`).Text() + actualCount, err := strconv.Atoi(countText) + if err != nil { + t.Fatalf("got count %q instead of integer", countText) + } + if actualCount < 1 { + t.Errorf("expected count >= 1, got %d", actualCount) + } +} + +type Event struct { + Type string + Data string +} + +func readSSE(ctx context.Context, url string, sse chan<- Event) (err error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return err + } + req.Header.Set("Cache-Control", "no-cache") + req.Header.Set("Accept", "text/event-stream") + req.Header.Set("Connection", "keep-alive") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + + var e Event + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + line := scanner.Text() + if line == "" { + sse <- e + e = Event{} + continue + } + if strings.HasPrefix(line, "event: ") { + e.Type = line[len("event: "):] + } + if strings.HasPrefix(line, "data: ") { + e.Data = line[len("data: "):] + } + } + return scanner.Err() +} + +func TestFileModificationsResultInSSEWithGzip(t *testing.T) { + if testing.Short() { + return + } + args, teardown, err := Setup(false) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + + // Start the SSE check. + events := make(chan Event) + var eventsErr error + go func() { + eventsErr = readSSE(context.Background(), fmt.Sprintf("%s/_templ/reload/events", args.ProxyURL), events) + }() + + // Assert data is expected. + doc, err := getHTML(args.ProxyURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + if text := doc.Find(`div[data-testid="modification"]`).Text(); text != "Original" { + t.Errorf("expected %q, got %q", "Original", text) + } + + // Change file. + templFile := filepath.Join(args.AppDir, "templates.templ") + err = replaceInFile(templFile, + `
Original
`, + `
Updated
`) + if err != nil { + t.Errorf("failed to replace text in file: %v", err) + } + + // Give the filesystem watcher a few seconds. + var reloadCount int +loop: + for { + select { + case event := <-events: + if event.Data == "reload" { + reloadCount++ + break loop + } + case <-time.After(time.Second * 5): + break loop + } + } + if reloadCount == 0 { + t.Error("failed to receive SSE about update after 5 seconds") + } + + // Check to see if there were any errors. + if eventsErr != nil { + t.Errorf("error reading events: %v", err) + } + + // See results in browser immediately. + doc, err = getHTML(args.ProxyURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + if text := doc.Find(`div[data-testid="modification"]`).Text(); text != "Updated" { + t.Errorf("expected %q, got %q", "Updated", text) + } +} + +func TestFileModificationsResultInSSE(t *testing.T) { + if testing.Short() { + return + } + args, teardown, err := Setup(false) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + + // Start the SSE check. + events := make(chan Event) + var eventsErr error + go func() { + eventsErr = readSSE(context.Background(), fmt.Sprintf("%s/_templ/reload/events", args.ProxyURL), events) + }() + + // Assert data is expected. + doc, err := getHTML(args.ProxyURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + if text := doc.Find(`div[data-testid="modification"]`).Text(); text != "Original" { + t.Errorf("expected %q, got %q", "Original", text) + } + + // Change file. + templFile := filepath.Join(args.AppDir, "templates.templ") + err = replaceInFile(templFile, + `
Original
`, + `
Updated
`) + if err != nil { + t.Errorf("failed to replace text in file: %v", err) + } + + // Give the filesystem watcher a few seconds. + var reloadCount int +loop: + for { + select { + case event := <-events: + if event.Data == "reload" { + reloadCount++ + break loop + } + case <-time.After(time.Second * 5): + break loop + } + } + if reloadCount == 0 { + t.Error("failed to receive SSE about update after 5 seconds") + } + + // Check to see if there were any errors. + if eventsErr != nil { + t.Errorf("error reading events: %v", err) + } + + // See results in browser immediately. + doc, err = getHTML(args.ProxyURL) + if err != nil { + t.Fatalf("failed to read HTML: %v", err) + } + if text := doc.Find(`div[data-testid="modification"]`).Text(); text != "Updated" { + t.Errorf("expected %q, got %q", "Updated", text) + } +} + +func NewTestArgs(modRoot, appDir string, appPort int, proxyBind string, proxyPort int) TestArgs { + return TestArgs{ + ModRoot: modRoot, + AppDir: appDir, + AppPort: appPort, + AppURL: fmt.Sprintf("http://localhost:%d", appPort), + ProxyBind: proxyBind, + ProxyPort: proxyPort, + ProxyURL: fmt.Sprintf("http://%s:%d", proxyBind, proxyPort), + } +} + +type TestArgs struct { + ModRoot string + AppDir string + AppPort int + AppURL string + ProxyBind string + ProxyPort int + ProxyURL string +} + +func Setup(gzipEncoding bool) (args TestArgs, teardown func(t *testing.T), err error) { + wd, err := os.Getwd() + if err != nil { + return args, teardown, fmt.Errorf("could not find working dir: %w", err) + } + moduleRoot, err := modcheck.WalkUp(wd) + if err != nil { + return args, teardown, fmt.Errorf("could not find local templ go.mod file: %v", err) + } + + appDir, err := createTestProject(moduleRoot) + if err != nil { + return args, teardown, fmt.Errorf("failed to create test project: %v", err) + } + appPort, err := getPort() + if err != nil { + return args, teardown, fmt.Errorf("failed to get available port: %v", err) + } + proxyPort, err := getPort() + if err != nil { + return args, teardown, fmt.Errorf("failed to get available port: %v", err) + } + proxyBind := "localhost" + + args = NewTestArgs(moduleRoot, appDir, appPort, proxyBind, proxyPort) + ctx, cancel := context.WithCancel(context.Background()) + + var wg sync.WaitGroup + var cmdErr error + + wg.Add(1) + go func() { + defer wg.Done() + + command := fmt.Sprintf("go run . -port %d", args.AppPort) + if gzipEncoding { + command += " -gzip true" + } + + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + + cmdErr = generatecmd.Run(ctx, log, generatecmd.Arguments{ + Path: appDir, + Watch: true, + OpenBrowser: false, + Command: command, + ProxyBind: proxyBind, + ProxyPort: proxyPort, + Proxy: args.AppURL, + NotifyProxy: false, + WorkerCount: 0, + GenerateSourceMapVisualisations: false, + IncludeVersion: false, + IncludeTimestamp: false, + PPROFPort: 0, + KeepOrphanedFiles: false, + }) + }() + + // Wait for server to start. + if err = waitForURL(args.AppURL); err != nil { + cancel() + wg.Wait() + return args, teardown, fmt.Errorf("failed to start app server, command error %v: %w", cmdErr, err) + } + if err = waitForURL(args.ProxyURL); err != nil { + cancel() + wg.Wait() + return args, teardown, fmt.Errorf("failed to start proxy server, command error %v: %w", cmdErr, err) + } + + // Wait for exit. + teardown = func(t *testing.T) { + cancel() + wg.Wait() + if cmdErr != nil { + t.Errorf("failed to run generate cmd: %v", err) + } + + if err = os.RemoveAll(appDir); err != nil { + t.Fatalf("failed to remove test dir %q: %v", appDir, err) + } + } + return args, teardown, err +} + +func waitForURL(url string) (err error) { + var tries int + for { + time.Sleep(time.Second) + if tries > 20 { + return err + } + tries++ + var resp *http.Response + resp, err = http.Get(url) + if err != nil { + fmt.Printf("failed to get %q: %v\n", url, err) + continue + } + if resp.StatusCode != http.StatusOK { + fmt.Printf("failed to get %q: %v\n", url, err) + err = fmt.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode) + continue + } + return nil + } +} + +func TestGenerateReturnsErrors(t *testing.T) { + wd, err := os.Getwd() + if err != nil { + t.Fatalf("could not find working dir: %v", err) + } + moduleRoot, err := modcheck.WalkUp(wd) + if err != nil { + t.Fatalf("could not find local templ go.mod file: %v", err) + } + + appDir, err := createTestProject(moduleRoot) + if err != nil { + t.Fatalf("failed to create test project: %v", err) + } + defer func() { + if err = os.RemoveAll(appDir); err != nil { + t.Fatalf("failed to remove test dir %q: %v", appDir, err) + } + }() + + // Break the HTML. + templFile := filepath.Join(appDir, "templates.templ") + err = replaceInFile(templFile, + `
Original
`, + `
`) + if err != nil { + t.Errorf("failed to replace text in file: %v", err) + } + + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + + // Run. + err = generatecmd.Run(context.Background(), log, generatecmd.Arguments{ + Path: appDir, + Watch: false, + IncludeVersion: false, + IncludeTimestamp: false, + KeepOrphanedFiles: false, + }) + if err == nil { + t.Errorf("expected generation error, got %v", err) + } +} diff --git a/templ/cmd/templ/generatecmd/testwatch/testdata/go.mod.embed b/templ/cmd/templ/generatecmd/testwatch/testdata/go.mod.embed new file mode 100644 index 0000000..bff4974 --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/testdata/go.mod.embed @@ -0,0 +1,7 @@ +module templ/testproject + +go 1.23 + +require github.com/a-h/templ v0.2.513 // indirect + +replace github.com/a-h/templ => {moduleRoot} diff --git a/templ/cmd/templ/generatecmd/testwatch/testdata/go.sum b/templ/cmd/templ/generatecmd/testwatch/testdata/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/testdata/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/cmd/templ/generatecmd/testwatch/testdata/main.go b/templ/cmd/templ/generatecmd/testwatch/testdata/main.go new file mode 100644 index 0000000..8ffd85d --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/testdata/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "bytes" + "compress/gzip" + "flag" + "fmt" + "log/slog" + "net/http" + "os" + "strconv" + + "github.com/a-h/templ" +) + +type GzipResponseWriter struct { + w http.ResponseWriter +} + +func (w *GzipResponseWriter) Header() http.Header { + return w.w.Header() +} + +func (w *GzipResponseWriter) Write(b []byte) (int, error) { + var buf bytes.Buffer + gzw := gzip.NewWriter(&buf) + defer gzw.Close() + + _, err := gzw.Write(b) + if err != nil { + return 0, err + } + err = gzw.Close() + if err != nil { + return 0, err + } + + w.w.Header().Set("Content-Length", strconv.Itoa(buf.Len())) + + return w.w.Write(buf.Bytes()) +} + +func (w *GzipResponseWriter) WriteHeader(statusCode int) { + w.w.WriteHeader(statusCode) +} + +var flagPort = flag.Int("port", 0, "Set the HTTP listen port") +var useGzip = flag.Bool("gzip", false, "Toggle gzip encoding") + +func main() { + flag.Parse() + + if *flagPort == 0 { + fmt.Println("missing port flag") + os.Exit(1) + } + + var count int + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if useGzip != nil && *useGzip { + w.Header().Set("Content-Encoding", "gzip") + w = &GzipResponseWriter{w: w} + } + + count++ + c := Page(count) + h := templ.Handler(c) + h.ErrorHandler = func(r *http.Request, err error) http.Handler { + slog.Error("failed to render template", slog.Any("error", err)) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, err.Error(), http.StatusInternalServerError) + }) + } + h.ServeHTTP(w, r) + }) + err := http.ListenAndServe(fmt.Sprintf("localhost:%d", *flagPort), nil) + if err != nil { + fmt.Printf("Error listening: %v\n", err) + os.Exit(1) + } +} diff --git a/templ/cmd/templ/generatecmd/testwatch/testdata/templates.templ b/templ/cmd/templ/generatecmd/testwatch/testdata/templates.templ new file mode 100644 index 0000000..c6c0394 --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/testdata/templates.templ @@ -0,0 +1,17 @@ +package main + +import "fmt" + +templ Page(count int) { + + + + templ test page + + +

Count

+
{ fmt.Sprintf("%d", count) }
+
Original
+ + +} diff --git a/templ/cmd/templ/generatecmd/testwatch/testdata/templates_templ.go b/templ/cmd/templ/generatecmd/testwatch/testdata/templates_templ.go new file mode 100644 index 0000000..0554521 --- /dev/null +++ b/templ/cmd/templ/generatecmd/testwatch/testdata/templates_templ.go @@ -0,0 +1,55 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func Page(count int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "templ test page

Count

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", count)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/generatecmd/testwatch/testdata/templates.templ`, Line: 13, Col: 54} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Original
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/generatecmd/watcher/watch.go b/templ/cmd/templ/generatecmd/watcher/watch.go new file mode 100644 index 0000000..8665603 --- /dev/null +++ b/templ/cmd/templ/generatecmd/watcher/watch.go @@ -0,0 +1,166 @@ +package watcher + +import ( + "context" + "io/fs" + "os" + "path" + "path/filepath" + "regexp" + "strings" + "sync" + "time" + + "github.com/fsnotify/fsnotify" +) + +func Recursive( + ctx context.Context, + path string, + watchPattern *regexp.Regexp, + out chan fsnotify.Event, + errors chan error, +) (w *RecursiveWatcher, err error) { + fsnw, err := fsnotify.NewWatcher() + if err != nil { + return nil, err + } + w = NewRecursiveWatcher(ctx, fsnw, watchPattern, out, errors) + go w.loop() + return w, w.Add(path) +} + +func NewRecursiveWatcher(ctx context.Context, w *fsnotify.Watcher, watchPattern *regexp.Regexp, events chan fsnotify.Event, errors chan error) *RecursiveWatcher { + return &RecursiveWatcher{ + ctx: ctx, + w: w, + WatchPattern: watchPattern, + Events: events, + Errors: errors, + timers: make(map[timerKey]*time.Timer), + } +} + +// WalkFiles walks the file tree rooted at path, sending a Create event for each +// file it encounters. +func WalkFiles(ctx context.Context, path string, watchPattern *regexp.Regexp, out chan fsnotify.Event) (err error) { + rootPath := path + fileSystem := os.DirFS(rootPath) + return fs.WalkDir(fileSystem, ".", func(path string, info os.DirEntry, err error) error { + if err != nil { + return nil + } + absPath, err := filepath.Abs(filepath.Join(rootPath, path)) + if err != nil { + return nil + } + if info.IsDir() && shouldSkipDir(absPath) { + return filepath.SkipDir + } + if !watchPattern.MatchString(absPath) { + return nil + } + out <- fsnotify.Event{ + Name: absPath, + Op: fsnotify.Create, + } + return nil + }) +} + +type RecursiveWatcher struct { + ctx context.Context + w *fsnotify.Watcher + WatchPattern *regexp.Regexp + Events chan fsnotify.Event + Errors chan error + timerMu sync.Mutex + timers map[timerKey]*time.Timer +} + +type timerKey struct { + name string + op fsnotify.Op +} + +func timerKeyFromEvent(event fsnotify.Event) timerKey { + return timerKey{ + name: event.Name, + op: event.Op, + } +} + +func (w *RecursiveWatcher) Close() error { + return w.w.Close() +} + +func (w *RecursiveWatcher) loop() { + for { + select { + case <-w.ctx.Done(): + return + case event, ok := <-w.w.Events: + if !ok { + return + } + if event.Has(fsnotify.Create) { + if err := w.Add(event.Name); err != nil { + w.Errors <- err + } + } + // Only notify on templ related files. + if !w.WatchPattern.MatchString(event.Name) { + continue + } + tk := timerKeyFromEvent(event) + w.timerMu.Lock() + t, ok := w.timers[tk] + w.timerMu.Unlock() + if !ok { + t = time.AfterFunc(100*time.Millisecond, func() { + w.Events <- event + }) + w.timerMu.Lock() + w.timers[tk] = t + w.timerMu.Unlock() + continue + } + t.Reset(100 * time.Millisecond) + case err, ok := <-w.w.Errors: + if !ok { + return + } + w.Errors <- err + } + } +} + +func (w *RecursiveWatcher) Add(dir string) error { + return filepath.WalkDir(dir, func(dir string, info os.DirEntry, err error) error { + if err != nil { + return nil + } + if !info.IsDir() { + return nil + } + if shouldSkipDir(dir) { + return filepath.SkipDir + } + return w.w.Add(dir) + }) +} + +func shouldSkipDir(dir string) bool { + if dir == "." { + return false + } + if dir == "vendor" || dir == "node_modules" { + return true + } + _, name := path.Split(dir) + // These directories are ignored by the Go tool. + if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") { + return true + } + return false +} diff --git a/templ/cmd/templ/generatecmd/watcher/watch_test.go b/templ/cmd/templ/generatecmd/watcher/watch_test.go new file mode 100644 index 0000000..39a560b --- /dev/null +++ b/templ/cmd/templ/generatecmd/watcher/watch_test.go @@ -0,0 +1,133 @@ +package watcher + +import ( + "context" + "fmt" + "regexp" + "testing" + "time" + + "github.com/fsnotify/fsnotify" +) + +func TestWatchDebouncesDuplicates(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + w := &fsnotify.Watcher{ + Events: make(chan fsnotify.Event), + } + events := make(chan fsnotify.Event, 2) + errors := make(chan error) + watchPattern, err := regexp.Compile(".*") + if err != nil { + t.Fatal(fmt.Errorf("failed to compile watch pattern: %w", err)) + } + rw := NewRecursiveWatcher(ctx, w, watchPattern, events, errors) + go func() { + rw.w.Events <- fsnotify.Event{Name: "test.templ"} + rw.w.Events <- fsnotify.Event{Name: "test.templ"} + cancel() + close(rw.w.Events) + }() + rw.loop() + count := 0 + exp := time.After(300 * time.Millisecond) + for { + select { + case <-rw.Events: + count++ + case <-exp: + if count != 1 { + t.Errorf("expected 1 event, got %d", count) + } + return + } + } +} + +func TestWatchDoesNotDebounceDifferentEvents(t *testing.T) { + tests := []struct { + event1 fsnotify.Event + event2 fsnotify.Event + }{ + // Different files + {fsnotify.Event{Name: "test.templ"}, fsnotify.Event{Name: "test2.templ"}}, + // Different operations + { + fsnotify.Event{Name: "test.templ", Op: fsnotify.Create}, + fsnotify.Event{Name: "test.templ", Op: fsnotify.Write}, + }, + // Different operations and files + { + fsnotify.Event{Name: "test.templ", Op: fsnotify.Create}, + fsnotify.Event{Name: "test2.templ", Op: fsnotify.Write}, + }, + } + for _, test := range tests { + ctx, cancel := context.WithCancel(context.Background()) + w := &fsnotify.Watcher{ + Events: make(chan fsnotify.Event), + } + events := make(chan fsnotify.Event, 2) + errors := make(chan error) + watchPattern, err := regexp.Compile(".*") + if err != nil { + t.Fatal(fmt.Errorf("failed to compile watch pattern: %w", err)) + } + rw := NewRecursiveWatcher(ctx, w, watchPattern, events, errors) + go func() { + rw.w.Events <- test.event1 + rw.w.Events <- test.event2 + cancel() + close(rw.w.Events) + }() + rw.loop() + count := 0 + exp := time.After(300 * time.Millisecond) + for { + select { + case <-rw.Events: + count++ + case <-exp: + if count != 2 { + t.Errorf("expected 2 event, got %d", count) + } + return + } + } + } +} + +func TestWatchDoesNotDebounceSeparateEvents(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + w := &fsnotify.Watcher{ + Events: make(chan fsnotify.Event), + } + events := make(chan fsnotify.Event, 2) + errors := make(chan error) + watchPattern, err := regexp.Compile(".*") + if err != nil { + t.Fatal(fmt.Errorf("failed to compile watch pattern: %w", err)) + } + rw := NewRecursiveWatcher(ctx, w, watchPattern, events, errors) + go func() { + rw.w.Events <- fsnotify.Event{Name: "test.templ"} + <-time.After(200 * time.Millisecond) + rw.w.Events <- fsnotify.Event{Name: "test.templ"} + cancel() + close(rw.w.Events) + }() + rw.loop() + count := 0 + exp := time.After(500 * time.Millisecond) + for { + select { + case <-rw.Events: + count++ + case <-exp: + if count != 2 { + t.Errorf("expected 2 event, got %d", count) + } + return + } + } +} diff --git a/templ/cmd/templ/imports/process.go b/templ/cmd/templ/imports/process.go new file mode 100644 index 0000000..d39c945 --- /dev/null +++ b/templ/cmd/templ/imports/process.go @@ -0,0 +1,174 @@ +package imports + +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/token" + "path" + "slices" + "strconv" + "strings" + + goparser "go/parser" + + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/imports" + + "github.com/a-h/templ/generator" + "github.com/a-h/templ/parser/v2" +) + +var internalImports = []string{"github.com/a-h/templ", "github.com/a-h/templ/runtime"} + +func convertTemplToGoURI(templURI string) (isTemplFile bool, goURI string) { + base, fileName := path.Split(templURI) + if !strings.HasSuffix(fileName, ".templ") { + return + } + return true, base + (strings.TrimSuffix(fileName, ".templ") + "_templ.go") +} + +var fset = token.NewFileSet() + +func updateImports(name, src string) (updated []*ast.ImportSpec, err error) { + // Apply auto imports. + updatedGoCode, err := imports.Process(name, []byte(src), nil) + if err != nil { + return updated, fmt.Errorf("failed to process go code %q: %w", src, err) + } + // Get updated imports. + gofile, err := goparser.ParseFile(fset, name, updatedGoCode, goparser.ImportsOnly) + if err != nil { + return updated, fmt.Errorf("failed to get imports from updated go code: %w", err) + } + for _, imp := range gofile.Imports { + if !slices.Contains(internalImports, strings.Trim(imp.Path.Value, "\"")) { + updated = append(updated, imp) + } + } + return updated, nil +} + +func Process(t parser.TemplateFile) (parser.TemplateFile, error) { + if t.Filepath == "" { + return t, nil + } + isTemplFile, fileName := convertTemplToGoURI(t.Filepath) + if !isTemplFile { + return t, fmt.Errorf("invalid filepath: %s", t.Filepath) + } + + // The first node always contains existing imports. + // If there isn't one, create it. + if len(t.Nodes) == 0 { + t.Nodes = append(t.Nodes, parser.TemplateFileGoExpression{}) + } + // If there is one, ensure it is a Go expression. + if _, ok := t.Nodes[0].(parser.TemplateFileGoExpression); !ok { + t.Nodes = append([]parser.TemplateFileNode{parser.TemplateFileGoExpression{}}, t.Nodes...) + } + + // Find all existing imports. + importsNode := t.Nodes[0].(parser.TemplateFileGoExpression) + + // Generate code. + gw := bytes.NewBuffer(nil) + var updatedImports []*ast.ImportSpec + var eg errgroup.Group + eg.Go(func() (err error) { + if _, err := generator.Generate(t, gw); err != nil { + return fmt.Errorf("failed to generate go code: %w", err) + } + updatedImports, err = updateImports(fileName, gw.String()) + if err != nil { + return fmt.Errorf("failed to get imports from generated go code: %w", err) + } + return nil + }) + + var firstGoNodeInTemplate *ast.File + // Update the template with the imports. + // Ensure that there is a Go expression to add the imports to as the first node. + eg.Go(func() (err error) { + firstGoNodeInTemplate, err = goparser.ParseFile(fset, fileName, t.Package.Expression.Value+"\n"+importsNode.Expression.Value, goparser.AllErrors|goparser.ParseComments) + if err != nil { + return fmt.Errorf("failed to parse imports section: %w", err) + } + return nil + }) + + // Wait for completion of both parts. + if err := eg.Wait(); err != nil { + return t, err + } + // Delete unused imports. + for _, imp := range firstGoNodeInTemplate.Imports { + if !containsImport(updatedImports, imp) { + name, path, err := getImportDetails(imp) + if err != nil { + return t, err + } + astutil.DeleteNamedImport(fset, firstGoNodeInTemplate, name, path) + } + } + // Add imports, if there are any to add. + for _, imp := range updatedImports { + if !containsImport(firstGoNodeInTemplate.Imports, imp) { + name, path, err := getImportDetails(imp) + if err != nil { + return t, err + } + astutil.AddNamedImport(fset, firstGoNodeInTemplate, name, path) + } + } + // Edge case: reinsert the import to use import syntax without parentheses. + if len(firstGoNodeInTemplate.Imports) == 1 { + name, path, err := getImportDetails(firstGoNodeInTemplate.Imports[0]) + if err != nil { + return t, err + } + astutil.DeleteNamedImport(fset, firstGoNodeInTemplate, name, path) + astutil.AddNamedImport(fset, firstGoNodeInTemplate, name, path) + } + // Write out the Go code with the imports. + updatedGoCode := new(strings.Builder) + err := format.Node(updatedGoCode, fset, firstGoNodeInTemplate) + if err != nil { + return t, fmt.Errorf("failed to write updated go code: %w", err) + } + // Remove the package statement from the node, by cutting the first line of the file. + importsNode.Expression.Value = strings.TrimSpace(strings.SplitN(updatedGoCode.String(), "\n", 2)[1]) + if len(updatedImports) == 0 && importsNode.Expression.Value == "" { + t.Nodes = t.Nodes[1:] + return t, nil + } + t.Nodes[0] = importsNode + return t, nil +} + +func getImportDetails(imp *ast.ImportSpec) (name, importPath string, err error) { + if imp.Name != nil { + name = imp.Name.Name + } + if imp.Path != nil { + importPath, err = strconv.Unquote(imp.Path.Value) + if err != nil { + err = fmt.Errorf("failed to unquote package path %s: %w", imp.Path.Value, err) + return + } + } + return name, importPath, nil +} + +func containsImport(imports []*ast.ImportSpec, spec *ast.ImportSpec) bool { + for _, imp := range imports { + if imp.Path.Value == spec.Path.Value { + return true + } + } + + return false +} diff --git a/templ/cmd/templ/imports/process_test.go b/templ/cmd/templ/imports/process_test.go new file mode 100644 index 0000000..7246527 --- /dev/null +++ b/templ/cmd/templ/imports/process_test.go @@ -0,0 +1,154 @@ +package imports + +import ( + "bytes" + "os" + "path" + "path/filepath" + "strings" + "testing" + + "github.com/a-h/templ/cmd/templ/testproject" + "github.com/a-h/templ/parser/v2" + "github.com/google/go-cmp/cmp" + "golang.org/x/tools/txtar" +) + +func TestFormatting(t *testing.T) { + files, _ := filepath.Glob("testdata/*.txtar") + if len(files) == 0 { + t.Errorf("no test files found") + } + for _, file := range files { + t.Run(filepath.Base(file), func(t *testing.T) { + a, err := txtar.ParseFile(file) + if err != nil { + t.Fatalf("failed to parse txtar file: %v", err) + } + if len(a.Files) != 2 { + t.Fatalf("expected 2 files, got %d", len(a.Files)) + } + template, err := parser.ParseString(clean(a.Files[0].Data)) + if err != nil { + t.Fatalf("failed to parse %v", err) + } + template.Filepath = a.Files[0].Name + tf, err := Process(template) + if err != nil { + t.Fatalf("failed to process file: %v", err) + } + expected := string(a.Files[1].Data) + actual := new(strings.Builder) + if err := tf.Write(actual); err != nil { + t.Fatalf("failed to write template file: %v", err) + } + if diff := cmp.Diff(expected, actual.String()); diff != "" { + t.Errorf("%s:\n%s", file, diff) + t.Errorf("expected:\n%s", showWhitespace(expected)) + t.Errorf("actual:\n%s", showWhitespace(actual.String())) + } + }) + } +} + +func showWhitespace(s string) string { + s = strings.ReplaceAll(s, "\n", "⏎\n") + s = strings.ReplaceAll(s, "\t", "→") + s = strings.ReplaceAll(s, " ", "·") + return s +} + +func clean(b []byte) string { + b = bytes.ReplaceAll(b, []byte("$\n"), []byte("\n")) + b = bytes.TrimSuffix(b, []byte("\n")) + return string(b) +} + +func TestImport(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + return + } + + tests := []struct { + name string + src string + assertions func(t *testing.T, updated string) + }{ + { + name: "un-named imports are removed", + src: `package main + +import "fmt" +import "github.com/a-h/templ/cmd/templ/testproject/css-classes" + +templ Page(count int) { + { fmt.Sprintf("%d", count) } + { cssclasses.Header } +} +`, + assertions: func(t *testing.T, updated string) { + if count := strings.Count(updated, "github.com/a-h/templ/cmd/templ/testproject/css-classes"); count != 0 { + t.Errorf("expected un-named import to be removed, but got %d instance of it", count) + } + }, + }, + { + name: "named imports are retained", + src: `package main + +import "fmt" +import cssclasses "github.com/a-h/templ/cmd/templ/testproject/css-classes" + +templ Page(count int) { + { fmt.Sprintf("%d", count) } + { cssclasses.Header } +} +`, + assertions: func(t *testing.T, updated string) { + if count := strings.Count(updated, "cssclasses \"github.com/a-h/templ/cmd/templ/testproject/css-classes\""); count != 1 { + t.Errorf("expected named import to be retained, got %d instances of it", count) + } + if count := strings.Count(updated, "github.com/a-h/templ/cmd/templ/testproject/css-classes"); count != 1 { + t.Errorf("expected one import, got %d", count) + } + }, + }, + } + + for _, test := range tests { + // Create test project. + dir, err := testproject.Create("github.com/a-h/templ/cmd/templ/testproject") + if err != nil { + t.Fatalf("failed to create test project: %v", err) + } + defer os.RemoveAll(dir) + + // Load the templates.templ file. + filePath := path.Join(dir, "templates.templ") + err = os.WriteFile(filePath, []byte(test.src), 0660) + if err != nil { + t.Fatalf("failed to write file: %v", err) + } + + // Parse the new file. + template, err := parser.Parse(filePath) + if err != nil { + t.Fatalf("failed to parse %v", err) + } + template.Filepath = filePath + tf, err := Process(template) + if err != nil { + t.Fatalf("failed to process file: %v", err) + } + + // Write it back out after processing. + buf := new(strings.Builder) + if err := tf.Write(buf); err != nil { + t.Fatalf("failed to write template file: %v", err) + } + + // Assert. + test.assertions(t, buf.String()) + } +} diff --git a/templ/cmd/templ/imports/testdata/comments.txtar b/templ/cmd/templ/imports/testdata/comments.txtar new file mode 100644 index 0000000..dd0f318 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/comments.txtar @@ -0,0 +1,12 @@ +-- fmt_templ.templ -- +package test + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") +-- fmt_templ.templ -- +package test + +import "fmt" + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") diff --git a/templ/cmd/templ/imports/testdata/commentsbeforepackage.txtar b/templ/cmd/templ/imports/testdata/commentsbeforepackage.txtar new file mode 100644 index 0000000..8585dc2 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/commentsbeforepackage.txtar @@ -0,0 +1,28 @@ +-- fmt_templ.templ -- +// Comments before. +/* + Some more comments +*/ +package test + +templ test() { +
Hello
+} + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") +-- fmt_templ.templ -- +// Comments before. +/* + Some more comments +*/ +package test + +import "fmt" + +templ test() { +
Hello
+} + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") diff --git a/templ/cmd/templ/imports/testdata/deleteimports.txtar b/templ/cmd/templ/imports/testdata/deleteimports.txtar new file mode 100644 index 0000000..674438e --- /dev/null +++ b/templ/cmd/templ/imports/testdata/deleteimports.txtar @@ -0,0 +1,14 @@ +-- fmt.templ -- +package test + +import "strconv" + +templ Hello() { +
Hello
+} +-- fmt.templ -- +package test + +templ Hello() { +
Hello
+} diff --git a/templ/cmd/templ/imports/testdata/extraspace.txtar b/templ/cmd/templ/imports/testdata/extraspace.txtar new file mode 100644 index 0000000..182513c --- /dev/null +++ b/templ/cmd/templ/imports/testdata/extraspace.txtar @@ -0,0 +1,15 @@ +-- fmt_templ.templ -- +package test + +const x = 123 + + +var x = fmt.Sprintf("Hello") +-- fmt_templ.templ -- +package test + +import "fmt" + +const x = 123 + +var x = fmt.Sprintf("Hello") diff --git a/templ/cmd/templ/imports/testdata/groups.txtar b/templ/cmd/templ/imports/testdata/groups.txtar new file mode 100644 index 0000000..1ff333f --- /dev/null +++ b/templ/cmd/templ/imports/testdata/groups.txtar @@ -0,0 +1,22 @@ +-- fmt.templ -- +package test + +import ( + "strings" + "fmt" + + "strconv" +) + +var _, _ = fmt.Print(strings.Contains(strconv.Quote("Hello"), "")) +-- fmt.templ -- +package test + +import ( + "fmt" + "strings" + + "strconv" +) + +var _, _ = fmt.Print(strings.Contains(strconv.Quote("Hello"), "")) diff --git a/templ/cmd/templ/imports/testdata/groupsmanynewlines.txtar b/templ/cmd/templ/imports/testdata/groupsmanynewlines.txtar new file mode 100644 index 0000000..9509be6 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/groupsmanynewlines.txtar @@ -0,0 +1,21 @@ +-- fmt.templ -- +package test + +import ( + "fmt" + + + "strconv" +) + +var _, _ = fmt.Print(strconv.Quote("Hello")) +-- fmt.templ -- +package test + +import ( + "fmt" + + "strconv" +) + +var _, _ = fmt.Print(strconv.Quote("Hello")) diff --git a/templ/cmd/templ/imports/testdata/header.txtar b/templ/cmd/templ/imports/testdata/header.txtar new file mode 100644 index 0000000..02a576e --- /dev/null +++ b/templ/cmd/templ/imports/testdata/header.txtar @@ -0,0 +1,10 @@ +-- fmt_templ.templ -- +package test + +var x = fmt.Sprintf("Hello") +-- fmt_templ.templ -- +package test + +import "fmt" + +var x = fmt.Sprintf("Hello") diff --git a/templ/cmd/templ/imports/testdata/namedimportsadd.txtar b/templ/cmd/templ/imports/testdata/namedimportsadd.txtar new file mode 100644 index 0000000..370f58d --- /dev/null +++ b/templ/cmd/templ/imports/testdata/namedimportsadd.txtar @@ -0,0 +1,19 @@ +-- fmt_templ.templ -- +package test + +import ( + sconv "strconv" +) + +// Comment on variable or function. +var x = fmt.Sprintf(sconv.Quote("Hello")) +-- fmt_templ.templ -- +package test + +import ( + "fmt" + sconv "strconv" +) + +// Comment on variable or function. +var x = fmt.Sprintf(sconv.Quote("Hello")) diff --git a/templ/cmd/templ/imports/testdata/namedimportsremoved.txtar b/templ/cmd/templ/imports/testdata/namedimportsremoved.txtar new file mode 100644 index 0000000..62c799e --- /dev/null +++ b/templ/cmd/templ/imports/testdata/namedimportsremoved.txtar @@ -0,0 +1,16 @@ +-- fmt_templ.templ -- +package test + +import ( + sconv "strconv" +) + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") +-- fmt_templ.templ -- +package test + +import "fmt" + +// Comment on variable or function. +var x = fmt.Sprintf("Hello") diff --git a/templ/cmd/templ/imports/testdata/noimports.txtar b/templ/cmd/templ/imports/testdata/noimports.txtar new file mode 100644 index 0000000..baa41a5 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/noimports.txtar @@ -0,0 +1,12 @@ +-- fmt.templ -- +package test + +templ Hello() { +
Hello
+} +-- fmt.templ -- +package test + +templ Hello() { +
Hello
+} diff --git a/templ/cmd/templ/imports/testdata/noimportscode.txtar b/templ/cmd/templ/imports/testdata/noimportscode.txtar new file mode 100644 index 0000000..4b67f41 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/noimportscode.txtar @@ -0,0 +1,20 @@ +-- fmt.templ -- +package test + +func test() { + // Do nothing. +} + +templ Hello() { +
Hello
+} +-- fmt.templ -- +package test + +func test() { + // Do nothing. +} + +templ Hello() { +
Hello
+} diff --git a/templ/cmd/templ/imports/testdata/stringexp.txtar b/templ/cmd/templ/imports/testdata/stringexp.txtar new file mode 100644 index 0000000..283023d --- /dev/null +++ b/templ/cmd/templ/imports/testdata/stringexp.txtar @@ -0,0 +1,14 @@ +-- fmt.templ -- +package test + +templ Hello(name string) { + { fmt.Sprintf("Hello, %s!", name) } +} +-- fmt.templ -- +package test + +import "fmt" + +templ Hello(name string) { + { fmt.Sprintf("Hello, %s!", name) } +} diff --git a/templ/cmd/templ/imports/testdata/twoimports.txtar b/templ/cmd/templ/imports/testdata/twoimports.txtar new file mode 100644 index 0000000..5da27e4 --- /dev/null +++ b/templ/cmd/templ/imports/testdata/twoimports.txtar @@ -0,0 +1,21 @@ +-- fmt.templ -- +package test + +templ Hello(name string) { +
+ { fmt.Sprintf("Hello, %s!", name) } +
+} +-- fmt.templ -- +package test + +import ( + "fmt" + "strconv" +) + +templ Hello(name string) { +
+ { fmt.Sprintf("Hello, %s!", name) } +
+} diff --git a/templ/cmd/templ/infocmd/main.go b/templ/cmd/templ/infocmd/main.go new file mode 100644 index 0000000..eddd932 --- /dev/null +++ b/templ/cmd/templ/infocmd/main.go @@ -0,0 +1,157 @@ +package infocmd + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log/slog" + "os" + "os/exec" + "runtime" + "strings" + + "github.com/a-h/templ" + "github.com/a-h/templ/cmd/templ/lspcmd/pls" +) + +type Arguments struct { + JSON bool `flag:"json" help:"Output info as JSON."` +} + +type Info struct { + OS struct { + GOOS string `json:"goos"` + GOARCH string `json:"goarch"` + } `json:"os"` + Go ToolInfo `json:"go"` + Gopls ToolInfo `json:"gopls"` + Templ ToolInfo `json:"templ"` +} + +type ToolInfo struct { + Location string `json:"location"` + Version string `json:"version"` + OK bool `json:"ok"` + Message string `json:"message,omitempty"` +} + +func getGoInfo() (d ToolInfo) { + // Find Go. + var err error + d.Location, err = exec.LookPath("go") + if err != nil { + d.Message = fmt.Sprintf("failed to find go: %v", err) + return + } + // Run go to find the version. + cmd := exec.Command(d.Location, "version") + v, err := cmd.Output() + if err != nil { + d.Message = fmt.Sprintf("failed to get go version, check that Go is installed: %v", err) + return + } + d.Version = strings.TrimSpace(string(v)) + d.OK = true + return +} + +func getGoplsInfo() (d ToolInfo) { + var err error + d.Location, err = pls.FindGopls() + if err != nil { + d.Message = fmt.Sprintf("failed to find gopls: %v", err) + return + } + cmd := exec.Command(d.Location, "version") + v, err := cmd.Output() + if err != nil { + d.Message = fmt.Sprintf("failed to get gopls version: %v", err) + return + } + d.Version = strings.TrimSpace(string(v)) + d.OK = true + return +} + +func getTemplInfo() (d ToolInfo) { + // Find templ. + var err error + d.Location, err = findTempl() + if err != nil { + d.Message = err.Error() + return + } + // Run templ to find the version. + cmd := exec.Command(d.Location, "version") + v, err := cmd.Output() + if err != nil { + d.Message = fmt.Sprintf("failed to get templ version: %v", err) + return + } + d.Version = strings.TrimSpace(string(v)) + if d.Version != templ.Version() { + d.Message = fmt.Sprintf("version mismatch - you're running %q at the command line, but the version in the path is %q", templ.Version(), d.Version) + return + } + d.OK = true + return +} + +func findTempl() (location string, err error) { + executableName := "templ" + if runtime.GOOS == "windows" { + executableName = "templ.exe" + } + executableName, err = exec.LookPath(executableName) + if err == nil { + // Found on the path. + return executableName, nil + } + + // Unexpected error. + if !errors.Is(err, exec.ErrNotFound) { + return "", fmt.Errorf("unexpected error looking for templ: %w", err) + } + + return "", fmt.Errorf("templ is not in the path (%q). You can install templ with `go install github.com/a-h/templ/cmd/templ@latest`", os.Getenv("PATH")) +} + +func getInfo() (d Info) { + d.OS.GOOS = runtime.GOOS + d.OS.GOARCH = runtime.GOARCH + d.Go = getGoInfo() + d.Gopls = getGoplsInfo() + d.Templ = getTemplInfo() + return +} + +func Run(ctx context.Context, log *slog.Logger, stdout io.Writer, args Arguments) (err error) { + info := getInfo() + if args.JSON { + enc := json.NewEncoder(stdout) + enc.SetIndent("", " ") + return enc.Encode(info) + } + log.Info("os", slog.String("goos", info.OS.GOOS), slog.String("goarch", info.OS.GOARCH)) + logInfo(ctx, log, "go", info.Go) + logInfo(ctx, log, "gopls", info.Gopls) + logInfo(ctx, log, "templ", info.Templ) + return nil +} + +func logInfo(ctx context.Context, log *slog.Logger, name string, ti ToolInfo) { + level := slog.LevelInfo + if !ti.OK { + level = slog.LevelError + } + args := []any{ + slog.String("location", ti.Location), + slog.String("version", ti.Version), + } + if ti.Message != "" { + args = append(args, slog.String("message", ti.Message)) + } + log.Log(ctx, level, name, args...) +} diff --git a/templ/cmd/templ/lspcmd/httpdebug/handler.go b/templ/cmd/templ/lspcmd/httpdebug/handler.go new file mode 100644 index 0000000..0f94502 --- /dev/null +++ b/templ/cmd/templ/lspcmd/httpdebug/handler.go @@ -0,0 +1,130 @@ +package httpdebug + +import ( + "encoding/json" + "io" + "log/slog" + "net/http" + "net/url" + + "github.com/a-h/templ" + "github.com/a-h/templ/cmd/templ/lspcmd/proxy" + "github.com/a-h/templ/cmd/templ/visualize" +) + +var log *slog.Logger + +func NewHandler(l *slog.Logger, s *proxy.Server) http.Handler { + m := http.NewServeMux() + log = l + m.HandleFunc("/templ", func(w http.ResponseWriter, r *http.Request) { + uri := r.URL.Query().Get("uri") + c, ok := s.TemplSource.Get(uri) + if !ok { + Error(w, "uri not found", http.StatusNotFound) + return + } + String(w, c.String()) + }) + m.HandleFunc("/sourcemap", func(w http.ResponseWriter, r *http.Request) { + uri := r.URL.Query().Get("uri") + sm, ok := s.SourceMapCache.Get(uri) + if !ok { + Error(w, "uri not found", http.StatusNotFound) + return + } + JSON(w, sm.SourceLinesToTarget) + }) + m.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) { + uri := r.URL.Query().Get("uri") + c, ok := s.GoSource[uri] + if !ok { + Error(w, "uri not found", http.StatusNotFound) + return + } + String(w, c) + }) + m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + uri := r.URL.Query().Get("uri") + if uri == "" { + // List all URIs. + if err := list(s.TemplSource.URIs()).Render(r.Context(), w); err != nil { + Error(w, "failed to list URIs", http.StatusInternalServerError) + } + return + } + // Assume we've got a URI. + templSource, ok := s.TemplSource.Get(uri) + if !ok { + if !ok { + Error(w, "uri not found in document contents", http.StatusNotFound) + return + } + } + goSource, ok := s.GoSource[uri] + if !ok { + if !ok { + Error(w, "uri not found in document contents", http.StatusNotFound) + return + } + } + sm, ok := s.SourceMapCache.Get(uri) + if !ok { + Error(w, "uri not found", http.StatusNotFound) + return + } + if err := visualize.HTML(uri, templSource.String(), goSource, sm).Render(r.Context(), w); err != nil { + Error(w, "failed to visualize HTML", http.StatusInternalServerError) + } + }) + return m +} + +func getMapURL(uri string) templ.SafeURL { + return withQuery("/", uri) +} + +func getSourceMapURL(uri string) templ.SafeURL { + return withQuery("/sourcemap", uri) +} + +func getTemplURL(uri string) templ.SafeURL { + return withQuery("/templ", uri) +} + +func getGoURL(uri string) templ.SafeURL { + return withQuery("/go", uri) +} + +func withQuery(path, uri string) templ.SafeURL { + q := make(url.Values) + q.Set("uri", uri) + u := &url.URL{ + Path: path, + RawPath: path, + RawQuery: q.Encode(), + } + return templ.SafeURL(u.String()) +} + +func JSON(w http.ResponseWriter, v any) { + w.Header().Set("Content-Type", "application/json") + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + if err := enc.Encode(v); err != nil { + log.Error("failed to write JSON response", slog.Any("error", err)) + } +} + +func String(w http.ResponseWriter, s string) { + if _, err := io.WriteString(w, s); err != nil { + log.Error("failed to write string response", slog.Any("error", err)) + } +} + +func Error(w http.ResponseWriter, msg string, status int) { + w.WriteHeader(status) + if _, err := io.WriteString(w, msg); err != nil { + log.Error("failed to write error response", slog.Any("error", err)) + } +} diff --git a/templ/cmd/templ/lspcmd/httpdebug/list.templ b/templ/cmd/templ/lspcmd/httpdebug/list.templ new file mode 100644 index 0000000..a1e7296 --- /dev/null +++ b/templ/cmd/templ/lspcmd/httpdebug/list.templ @@ -0,0 +1,22 @@ +package httpdebug + +templ list(uris []string) { + + + + + + + + + for _, uri := range uris { + + + + + + + + } +
File
{ uri }MappingSource MapTemplGo
+} diff --git a/templ/cmd/templ/lspcmd/httpdebug/list_templ.go b/templ/cmd/templ/lspcmd/httpdebug/list_templ.go new file mode 100644 index 0000000..b416b0b --- /dev/null +++ b/templ/cmd/templ/lspcmd/httpdebug/list_templ.go @@ -0,0 +1,99 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package httpdebug + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func list(uris []string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, uri := range uris { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
File
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(uri) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/lspcmd/httpdebug/list.templ`, Line: 14, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "MappingSource MapTemplGo
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/lspcmd/lsp_test.go b/templ/cmd/templ/lspcmd/lsp_test.go new file mode 100644 index 0000000..8d36e64 --- /dev/null +++ b/templ/cmd/templ/lspcmd/lsp_test.go @@ -0,0 +1,957 @@ +package lspcmd + +import ( + "context" + "fmt" + "io" + "log/slog" + "os" + "sync" + "testing" + "time" + "unicode/utf8" + + "github.com/a-h/templ/cmd/templ/generatecmd/modcheck" + "github.com/a-h/templ/cmd/templ/lspcmd/lspdiff" + "github.com/a-h/templ/cmd/templ/testproject" + "github.com/a-h/templ/lsp/jsonrpc2" + "github.com/a-h/templ/lsp/protocol" + "github.com/a-h/templ/lsp/uri" + "github.com/google/go-cmp/cmp" +) + +func TestCompletion(t *testing.T) { + if testing.Short() { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + ctx, appDir, _, server, teardown, err := Setup(ctx, log) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + defer cancel() + + templFile, err := os.ReadFile(appDir + "/templates.templ") + if err != nil { + t.Errorf("failed to read file %q: %v", appDir+"/templates.templ", err) + return + } + err = server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ + TextDocument: protocol.TextDocumentItem{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + LanguageID: "templ", + Version: 1, + Text: string(templFile), + }, + }) + if err != nil { + t.Errorf("failed to register open file: %v", err) + return + } + log.Info("Calling completion") + + globalSnippetsLen := 1 + + // Edit the file. + // Replace: + //
{ fmt.Sprintf("%d", count) }
+ // With various tests: + //
{ f + tests := []struct { + line int + replacement string + cursor string + assert func(t *testing.T, cl *protocol.CompletionList) (msg string, ok bool) + }{ + { + line: 13, + replacement: `
{ `, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.CompletionList) (msg string, ok bool) { + if actual != nil && len(actual.Items) != globalSnippetsLen { + return "expected completion list to be empty", false + } + return "", true + }, + }, + { + line: 13, + replacement: `
{ fmt.`, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.CompletionList) (msg string, ok bool) { + if !lspdiff.CompletionListContainsText(actual, "fmt.Sprintf") { + return fmt.Sprintf("expected fmt.Sprintf to be in the completion list, but got %#v", actual), false + } + return "", true + }, + }, + { + line: 13, + replacement: `
{ fmt.Sprintf("%d",`, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.CompletionList) (msg string, ok bool) { + if actual != nil && len(actual.Items) != globalSnippetsLen { + return "expected completion list to be empty", false + } + return "", true + }, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) { + // Edit the file. + updated := testproject.MustReplaceLine(string(templFile), test.line, test.replacement) + err = server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{ + TextDocument: protocol.VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + Version: int32(i + 2), + }, + ContentChanges: []protocol.TextDocumentContentChangeEvent{ + { + Range: nil, + Text: updated, + }, + }, + }) + if err != nil { + t.Errorf("failed to change file: %v", err) + return + } + + // Give CI/CD pipeline executors some time because they're often quite slow. + var ok bool + var msg string + for i := 0; i < 3; i++ { + actual, err := server.Completion(ctx, &protocol.CompletionParams{ + Context: &protocol.CompletionContext{ + TriggerCharacter: ".", + TriggerKind: protocol.CompletionTriggerKindTriggerCharacter, + }, + TextDocumentPositionParams: protocol.TextDocumentPositionParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + // Positions are zero indexed. + Position: protocol.Position{ + Line: uint32(test.line - 1), + Character: uint32(len(test.cursor) - 1), + }, + }, + }) + if err != nil { + t.Errorf("failed to get completion: %v", err) + return + } + msg, ok = test.assert(t, actual) + if !ok { + break + } + time.Sleep(time.Millisecond * 500) + } + if !ok { + t.Error(msg) + } + }) + } + log.Info("Completed test") +} + +func TestHover(t *testing.T) { + if testing.Short() { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + ctx, appDir, _, server, teardown, err := Setup(ctx, log) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + defer cancel() + + templFile, err := os.ReadFile(appDir + "/templates.templ") + if err != nil { + t.Fatalf("failed to read file %q: %v", appDir+"/templates.templ", err) + } + err = server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ + TextDocument: protocol.TextDocumentItem{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + LanguageID: "templ", + Version: 1, + Text: string(templFile), + }, + }) + if err != nil { + t.Errorf("failed to register open file: %v", err) + return + } + log.Info("Calling hover") + + // Edit the file. + // Replace: + //
{ fmt.Sprintf("%d", count) }
+ // With various tests: + //
{ f + tests := []struct { + line int + replacement string + cursor string + assert func(t *testing.T, hr *protocol.Hover) (msg string, ok bool) + }{ + { + line: 13, + replacement: `
{ fmt.Sprintf("%d", count) }
`, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.Hover) (msg string, ok bool) { + expectedHover := protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: "markdown", + Value: "```go\npackage fmt\n```\n\n---\n\n[`fmt` on pkg.go.dev](https://pkg.go.dev/fmt)", + }, + } + if diff := lspdiff.Hover(expectedHover, *actual); diff != "" { + return fmt.Sprintf("unexpected hover: %v\n\n: markdown: %#v", diff, actual.Contents.Value), false + } + return "", true + }, + }, + { + line: 13, + replacement: `
{ fmt.Sprintf("%d", count) }
`, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.Hover) (msg string, ok bool) { + expectedHover := protocol.Hover{ + Contents: protocol.MarkupContent{ + Kind: "markdown", + Value: "```go\nfunc fmt.Sprintf(format string, a ...any) string\n```\n\n---\n\nSprintf formats according to a format specifier and returns the resulting string.\n\n\n---\n\n[`fmt.Sprintf` on pkg.go.dev](https://pkg.go.dev/fmt#Sprintf)", + }, + } + if actual == nil { + return "expected hover to be non-nil", false + } + if diff := lspdiff.Hover(expectedHover, *actual); diff != "" { + return fmt.Sprintf("unexpected hover: %v", diff), false + } + return "", true + }, + }, + { + line: 19, + replacement: `var nihao = "你好"`, + cursor: ` ^`, + assert: func(t *testing.T, actual *protocol.Hover) (msg string, ok bool) { + // There's nothing to hover, just want to make sure it doesn't panic. + return "", true + }, + }, + { + line: 19, + replacement: `var nihao = "你好"`, + cursor: ` ^`, // Your text editor might not render this well, but it's the hao. + assert: func(t *testing.T, actual *protocol.Hover) (msg string, ok bool) { + // There's nothing to hover, just want to make sure it doesn't panic. + return "", true + }, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) { + // Put the file back to the initial point. + err = server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{ + TextDocument: protocol.VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + Version: int32(i + 2), + }, + ContentChanges: []protocol.TextDocumentContentChangeEvent{ + { + Range: nil, + Text: string(templFile), + }, + }, + }) + if err != nil { + t.Errorf("failed to change file: %v", err) + return + } + + // Give CI/CD pipeline executors some time because they're often quite slow. + var ok bool + var msg string + for i := 0; i < 3; i++ { + lspCharIndex, err := runeIndexToUTF8ByteIndex(test.replacement, len(test.cursor)-1) + if err != nil { + t.Error(err) + } + actual, err := server.Hover(ctx, &protocol.HoverParams{ + TextDocumentPositionParams: protocol.TextDocumentPositionParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + // Positions are zero indexed. + Position: protocol.Position{ + Line: uint32(test.line - 1), + Character: lspCharIndex, + }, + }, + }) + if err != nil { + t.Errorf("failed to hover: %v", err) + return + } + msg, ok = test.assert(t, actual) + if !ok { + break + } + time.Sleep(time.Millisecond * 500) + } + if !ok { + t.Error(msg) + } + }) + } +} + +func TestReferences(t *testing.T) { + if testing.Short() { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + ctx, appDir, _, server, teardown, err := Setup(ctx, log) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + return + } + defer teardown(t) + defer cancel() + + log.Info("Calling References") + + tests := []struct { + line int + character int + filename string + assert func(t *testing.T, l []protocol.Location) (msg string, ok bool) + }{ + { + // this is the definition of the templ function in the templates.templ file. + line: 5, + character: 9, + filename: "/templates.templ", + assert: func(t *testing.T, actual []protocol.Location) (msg string, ok bool) { + expectedReference := []protocol.Location{ + { + // This is the usage of the templ function in the main.go file. + URI: uri.URI("file://" + appDir + "/main.go"), + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(24), + Character: uint32(7), + }, + End: protocol.Position{ + Line: uint32(24), + Character: uint32(11), + }, + }, + }, + } + if diff := lspdiff.References(expectedReference, actual); diff != "" { + return fmt.Sprintf("Expected: %+v\nActual: %+v", expectedReference, actual), false + } + return "", true + }, + }, + { + // this is the definition of the struct in the templates.templ file. + line: 21, + character: 9, + filename: "/templates.templ", + assert: func(t *testing.T, actual []protocol.Location) (msg string, ok bool) { + expectedReference := []protocol.Location{ + { + // This is the usage of the struct in the templates.templ file. + URI: uri.URI("file://" + appDir + "/templates.templ"), + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(24), + Character: uint32(8), + }, + End: protocol.Position{ + Line: uint32(24), + Character: uint32(14), + }, + }, + }, + } + if diff := lspdiff.References(expectedReference, actual); diff != "" { + return fmt.Sprintf("Expected: %+v\nActual: %+v", expectedReference, actual), false + } + return "", true + }, + }, + { + // this test is for inclusions from a remote file that has not been explicitly called with didOpen + line: 3, + character: 9, + filename: "/remotechild.templ", + assert: func(t *testing.T, actual []protocol.Location) (msg string, ok bool) { + expectedReference := []protocol.Location{ + { + URI: uri.URI("file://" + appDir + "/remoteparent.templ"), + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(3), + Character: uint32(2), + }, + End: protocol.Position{ + Line: uint32(3), + Character: uint32(8), + }, + }, + }, + { + URI: uri.URI("file://" + appDir + "/remoteparent.templ"), + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(7), + Character: uint32(2), + }, + End: protocol.Position{ + Line: uint32(7), + Character: uint32(8), + }, + }, + }, + } + if diff := lspdiff.References(expectedReference, actual); diff != "" { + return fmt.Sprintf("Expected: %+v\nActual: %+v", expectedReference, actual), false + } + return "", true + }, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) { + // Give CI/CD pipeline executors some time because they're often quite slow. + var ok bool + var msg string + for i := 0; i < 3; i++ { + if err != nil { + t.Error(err) + return + } + actual, err := server.References(ctx, &protocol.ReferenceParams{ + TextDocumentPositionParams: protocol.TextDocumentPositionParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + test.filename), + }, + // Positions are zero indexed. + Position: protocol.Position{ + Line: uint32(test.line - 1), + Character: uint32(test.character - 1), + }, + }, + }) + if err != nil { + t.Errorf("failed to get references: %v", err) + return + } + msg, ok = test.assert(t, actual) + if !ok { + break + } + time.Sleep(time.Millisecond * 500) + } + if !ok { + t.Error(msg) + } + }) + } +} + +func TestCodeAction(t *testing.T) { + if testing.Short() { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + ctx, appDir, _, server, teardown, err := Setup(ctx, log) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + defer cancel() + + templFile, err := os.ReadFile(appDir + "/templates.templ") + if err != nil { + t.Fatalf("failed to read file %q: %v", appDir+"/templates.templ", err) + } + err = server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{ + TextDocument: protocol.TextDocumentItem{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + LanguageID: "templ", + Version: 1, + Text: string(templFile), + }, + }) + if err != nil { + t.Errorf("failed to register open file: %v", err) + return + } + log.Info("Calling codeAction") + + tests := []struct { + line int + replacement string + cursor string + assert func(t *testing.T, hr []protocol.CodeAction) (msg string, ok bool) + }{ + { + line: 25, + replacement: `var s = Struct{}`, + cursor: ` ^`, + assert: func(t *testing.T, actual []protocol.CodeAction) (msg string, ok bool) { + var expected []protocol.CodeAction + // To support code actions, update cmd/templ/lspcmd/proxy/server.go and add the + // Title (e.g. Organize Imports, or Fill Struct) to the supportedCodeActions map. + + // Some Code Actions are simple edits, so all that is needed is for the server + // to remap the source code positions. + + // However, other Code Actions are commands, where the arguments must be rewritten + // and will need to be handled individually. + if diff := lspdiff.CodeAction(expected, actual); diff != "" { + return fmt.Sprintf("unexpected codeAction: %v", diff), false + } + return "", true + }, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) { + // Put the file back to the initial point. + err = server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{ + TextDocument: protocol.VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + Version: int32(i + 2), + }, + ContentChanges: []protocol.TextDocumentContentChangeEvent{ + { + Range: nil, + Text: string(templFile), + }, + }, + }) + if err != nil { + t.Errorf("failed to change file: %v", err) + return + } + + // Give CI/CD pipeline executors some time because they're often quite slow. + var ok bool + var msg string + for i := 0; i < 3; i++ { + lspCharIndex, err := runeIndexToUTF8ByteIndex(test.replacement, len(test.cursor)-1) + if err != nil { + t.Error(err) + } + actual, err := server.CodeAction(ctx, &protocol.CodeActionParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: uri.URI("file://" + appDir + "/templates.templ"), + }, + Range: protocol.Range{ + Start: protocol.Position{ + Line: uint32(test.line - 1), + Character: lspCharIndex, + }, + End: protocol.Position{ + Line: uint32(test.line - 1), + Character: lspCharIndex + 1, + }, + }, + }) + if err != nil { + t.Errorf("failed code action: %v", err) + return + } + msg, ok = test.assert(t, actual) + if !ok { + break + } + time.Sleep(time.Millisecond * 500) + } + if !ok { + t.Error(msg) + } + }) + } +} + +func TestDocumentSymbol(t *testing.T) { + if testing.Short() { + return + } + + ctx, cancel := context.WithCancel(context.Background()) + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + ctx, appDir, _, server, teardown, err := Setup(ctx, log) + if err != nil { + t.Fatalf("failed to setup test: %v", err) + } + defer teardown(t) + defer cancel() + + tests := []struct { + uri string + expect []protocol.SymbolInformationOrDocumentSymbol + }{ + { + uri: "file://" + appDir + "/templates.templ", + expect: []protocol.SymbolInformationOrDocumentSymbol{ + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "Page", + Kind: protocol.SymbolKindFunction, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 11, Character: 0}, + End: protocol.Position{Line: 50, Character: 1}, + }, + }, + }, + }, + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "nihao", + Kind: protocol.SymbolKindVariable, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 18, Character: 4}, + End: protocol.Position{Line: 18, Character: 16}, + }, + }, + }, + }, + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "Struct", + Kind: protocol.SymbolKindStruct, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 20, Character: 5}, + End: protocol.Position{Line: 22, Character: 1}, + }, + }, + }, + }, + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "s", + Kind: protocol.SymbolKindVariable, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 24, Character: 4}, + End: protocol.Position{Line: 24, Character: 16}, + }, + }, + }, + }, + }, + }, + { + uri: "file://" + appDir + "/remoteparent.templ", + expect: []protocol.SymbolInformationOrDocumentSymbol{ + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "RemoteInclusionTest", + Kind: protocol.SymbolKindFunction, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 9, Character: 0}, + End: protocol.Position{Line: 35, Character: 1}, + }, + }, + }, + }, + { + SymbolInformation: &protocol.SymbolInformation{ + Name: "Remote2", + Kind: protocol.SymbolKindFunction, + Location: protocol.Location{ + Range: protocol.Range{ + Start: protocol.Position{Line: 37, Character: 0}, + End: protocol.Position{Line: 63, Character: 1}, + }, + }, + }, + }, + }, + }, + } + + for i, test := range tests { + t.Run(fmt.Sprintf("test-%d", i), func(t *testing.T) { + actual, err := server.DocumentSymbol(ctx, &protocol.DocumentSymbolParams{ + TextDocument: protocol.TextDocumentIdentifier{ + URI: uri.URI(test.uri), + }, + }) + if err != nil { + t.Errorf("failed to get document symbol: %v", err) + } + + // Set expected URI. + for i, v := range test.expect { + if v.SymbolInformation != nil { + v.SymbolInformation.Location.URI = uri.URI(test.uri) + test.expect[i] = v + } + } + + if err != nil { + t.Errorf("failed to convert expect to any slice: %v", err) + } + diff := cmp.Diff(test.expect, actual) + if diff != "" { + t.Errorf("unexpected document symbol: %v", diff) + } + }) + } +} + +func runeIndexToUTF8ByteIndex(s string, runeIndex int) (lspChar uint32, err error) { + for i, r := range []rune(s) { + if i == runeIndex { + break + } + l := utf8.RuneLen(r) + if l < 0 { + return 0, fmt.Errorf("invalid rune in string at index %d", runeIndex) + } + lspChar += uint32(l) + } + return lspChar, nil +} + +func NewTestClient(log *slog.Logger) TestClient { + return TestClient{ + log: log, + } +} + +type TestClient struct { + log *slog.Logger +} + +func (tc TestClient) Progress(ctx context.Context, params *protocol.ProgressParams) (err error) { + tc.log.Info("client: Received Progress", slog.Any("params", params)) + return nil +} + +func (tc TestClient) WorkDoneProgressCreate(ctx context.Context, params *protocol.WorkDoneProgressCreateParams) (err error) { + tc.log.Info("client: Received WorkDoneProgressCreate", slog.Any("params", params)) + return nil +} + +func (tc TestClient) LogMessage(ctx context.Context, params *protocol.LogMessageParams) (err error) { + tc.log.Info("client: Received LogMessage", slog.Any("params", params)) + return nil +} + +func (tc TestClient) PublishDiagnostics(ctx context.Context, params *protocol.PublishDiagnosticsParams) (err error) { + tc.log.Info("client: Received PublishDiagnostics", slog.Any("params", params)) + return nil +} + +func (tc TestClient) ShowMessage(ctx context.Context, params *protocol.ShowMessageParams) (err error) { + tc.log.Info("client: Received ShowMessage", slog.Any("params", params)) + return nil +} + +func (tc TestClient) ShowMessageRequest(ctx context.Context, params *protocol.ShowMessageRequestParams) (result *protocol.MessageActionItem, err error) { + return nil, nil +} + +func (tc TestClient) Telemetry(ctx context.Context, params any) (err error) { + tc.log.Info("client: Received Telemetry", slog.Any("params", params)) + return nil +} + +func (tc TestClient) RegisterCapability(ctx context.Context, params *protocol.RegistrationParams, +) (err error) { + tc.log.Info("client: Received RegisterCapability", slog.Any("params", params)) + return nil +} + +func (tc TestClient) UnregisterCapability(ctx context.Context, params *protocol.UnregistrationParams) (err error) { + tc.log.Info("client: Received UnregisterCapability", slog.Any("params", params)) + return nil +} + +func (tc TestClient) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (result *protocol.ApplyWorkspaceEditResponse, err error) { + tc.log.Info("client: Received ApplyEdit", slog.Any("params", params)) + return nil, nil +} + +func (tc TestClient) Configuration(ctx context.Context, params *protocol.ConfigurationParams) (result []any, err error) { + tc.log.Info("client: Received Configuration", slog.Any("params", params)) + return nil, nil +} + +func (tc TestClient) WorkspaceFolders(ctx context.Context) (result []protocol.WorkspaceFolder, err error) { + tc.log.Info("client: Received WorkspaceFolders") + return nil, nil +} + +func Setup(ctx context.Context, log *slog.Logger) (clientCtx context.Context, appDir string, client protocol.Client, server protocol.Server, teardown func(t *testing.T), err error) { + wd, err := os.Getwd() + if err != nil { + return ctx, appDir, client, server, teardown, fmt.Errorf("could not find working dir: %w", err) + } + moduleRoot, err := modcheck.WalkUp(wd) + if err != nil { + return ctx, appDir, client, server, teardown, fmt.Errorf("could not find local templ go.mod file: %v", err) + } + + appDir, err = testproject.Create(moduleRoot) + if err != nil { + return ctx, appDir, client, server, teardown, fmt.Errorf("failed to create test project: %v", err) + } + + var wg sync.WaitGroup + var cmdErr error + + // Copy from the LSP to the Client, and vice versa. + fromClient, toLSP := io.Pipe() + fromLSP, toClient := io.Pipe() + clientStream := jsonrpc2.NewStream(newStdRwc(log, "clientStream", toLSP, fromLSP)) + serverStream := jsonrpc2.NewStream(newStdRwc(log, "serverStream", toClient, fromClient)) + + // Create the client that the server needs. + client = NewTestClient(log) + ctx, _, server = protocol.NewClient(ctx, client, clientStream, log) + + wg.Add(1) + go func() { + defer wg.Done() + log.Info("Running") + // Create the server that the client needs. + cmdErr = run(ctx, log, serverStream, Arguments{}) + if cmdErr != nil { + log.Error("Failed to run", slog.Any("error", cmdErr)) + } + log.Info("Stopped") + }() + + // Initialize. + ir, err := server.Initialize(ctx, &protocol.InitializeParams{ + ClientInfo: &protocol.ClientInfo{}, + Capabilities: protocol.ClientCapabilities{ + Workspace: &protocol.WorkspaceClientCapabilities{ + ApplyEdit: true, + WorkspaceEdit: &protocol.WorkspaceClientCapabilitiesWorkspaceEdit{ + DocumentChanges: true, + }, + WorkspaceFolders: true, + FileOperations: &protocol.WorkspaceClientCapabilitiesFileOperations{ + DidCreate: true, + WillCreate: true, + DidRename: true, + WillRename: true, + DidDelete: true, + WillDelete: true, + }, + }, + TextDocument: &protocol.TextDocumentClientCapabilities{ + Synchronization: &protocol.TextDocumentSyncClientCapabilities{ + DidSave: true, + }, + Completion: &protocol.CompletionTextDocumentClientCapabilities{ + CompletionItem: &protocol.CompletionTextDocumentClientCapabilitiesItem{ + SnippetSupport: true, + DeprecatedSupport: true, + InsertReplaceSupport: true, + }, + }, + Hover: &protocol.HoverTextDocumentClientCapabilities{}, + SignatureHelp: &protocol.SignatureHelpTextDocumentClientCapabilities{}, + Declaration: &protocol.DeclarationTextDocumentClientCapabilities{}, + Definition: &protocol.DefinitionTextDocumentClientCapabilities{}, + TypeDefinition: &protocol.TypeDefinitionTextDocumentClientCapabilities{}, + Implementation: &protocol.ImplementationTextDocumentClientCapabilities{}, + References: &protocol.ReferencesTextDocumentClientCapabilities{}, + DocumentHighlight: &protocol.DocumentHighlightClientCapabilities{}, + DocumentSymbol: &protocol.DocumentSymbolClientCapabilities{}, + CodeAction: &protocol.CodeActionClientCapabilities{}, + CodeLens: &protocol.CodeLensClientCapabilities{}, + Formatting: &protocol.DocumentFormattingClientCapabilities{}, + RangeFormatting: &protocol.DocumentRangeFormattingClientCapabilities{}, + OnTypeFormatting: &protocol.DocumentOnTypeFormattingClientCapabilities{}, + PublishDiagnostics: &protocol.PublishDiagnosticsClientCapabilities{}, + Rename: &protocol.RenameClientCapabilities{}, + FoldingRange: &protocol.FoldingRangeClientCapabilities{}, + SelectionRange: &protocol.SelectionRangeClientCapabilities{}, + CallHierarchy: &protocol.CallHierarchyClientCapabilities{}, + SemanticTokens: &protocol.SemanticTokensClientCapabilities{}, + LinkedEditingRange: &protocol.LinkedEditingRangeClientCapabilities{}, + }, + Window: &protocol.WindowClientCapabilities{}, + General: &protocol.GeneralClientCapabilities{}, + Experimental: nil, + }, + WorkspaceFolders: []protocol.WorkspaceFolder{ + { + URI: "file://" + appDir, + Name: "templ-test", + }, + }, + }) + if err != nil { + log.Error("Failed to init", slog.Any("error", err)) + } + if ir.ServerInfo.Name != "templ-lsp" { + return ctx, appDir, client, server, teardown, fmt.Errorf("expected server name to be templ-lsp, got %q", ir.ServerInfo.Name) + } + + // Confirm initialization. + log.Info("Confirming initialization...") + if err = server.Initialized(ctx, &protocol.InitializedParams{}); err != nil { + return ctx, appDir, client, server, teardown, fmt.Errorf("failed to confirm initialization: %v", err) + } + log.Info("Initialized") + + // Wait for exit. + teardown = func(t *testing.T) { + log.Info("Tearing down LSP") + wg.Wait() + if cmdErr != nil { + t.Errorf("failed to run lsp cmd: %v", err) + } + + if err = os.RemoveAll(appDir); err != nil { + t.Errorf("failed to remove test dir %q: %v", appDir, err) + } + } + return ctx, appDir, client, server, teardown, err +} diff --git a/templ/cmd/templ/lspcmd/lspdiff/lspdiff.go b/templ/cmd/templ/lspcmd/lspdiff/lspdiff.go new file mode 100644 index 0000000..847d381 --- /dev/null +++ b/templ/cmd/templ/lspcmd/lspdiff/lspdiff.go @@ -0,0 +1,42 @@ +package lspdiff + +import ( + "github.com/a-h/templ/lsp/protocol" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +// This package provides a way to compare LSP protocol messages, ignoring irrelevant fields. + +func Hover(expected, actual protocol.Hover) string { + return cmp.Diff(expected, actual, + cmpopts.IgnoreFields(protocol.Hover{}, "Range"), + cmpopts.IgnoreFields(protocol.MarkupContent{}, "Kind"), + ) +} + +func CodeAction(expected, actual []protocol.CodeAction) string { + return cmp.Diff(expected, actual) +} + +func CompletionList(expected, actual *protocol.CompletionList) string { + return cmp.Diff(expected, actual, + cmpopts.IgnoreFields(protocol.CompletionList{}, "IsIncomplete"), + ) +} + +func References(expected, actual []protocol.Location) string { + return cmp.Diff(expected, actual) +} + +func CompletionListContainsText(cl *protocol.CompletionList, text string) bool { + if cl == nil { + return false + } + for _, item := range cl.Items { + if item.Label == text { + return true + } + } + return false +} diff --git a/templ/cmd/templ/lspcmd/main.go b/templ/cmd/templ/lspcmd/main.go new file mode 100644 index 0000000..b0d41c8 --- /dev/null +++ b/templ/cmd/templ/lspcmd/main.go @@ -0,0 +1,131 @@ +package lspcmd + +import ( + "context" + "fmt" + "io" + "log/slog" + "net/http" + "os" + "os/signal" + + "github.com/a-h/templ/cmd/templ/lspcmd/httpdebug" + "github.com/a-h/templ/cmd/templ/lspcmd/pls" + "github.com/a-h/templ/cmd/templ/lspcmd/proxy" + "github.com/a-h/templ/lsp/jsonrpc2" + "github.com/a-h/templ/lsp/protocol" + + _ "net/http/pprof" +) + +type Arguments struct { + Log string + GoplsLog string + GoplsRPCTrace bool + // PPROF sets whether to start a profiling server on localhost:9999 + PPROF bool + // HTTPDebug sets the HTTP endpoint to listen on. Leave empty for no web debug. + HTTPDebug string +} + +func Run(stdin io.Reader, stdout, stderr io.Writer, args Arguments) (err error) { + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + defer func() { + signal.Stop(signalChan) + cancel() + }() + if args.PPROF { + go func() { + _ = http.ListenAndServe("localhost:9999", nil) + }() + } + go func() { + select { + case <-signalChan: // First signal, cancel context. + cancel() + case <-ctx.Done(): + } + <-signalChan // Second signal, hard exit. + os.Exit(2) + }() + log := slog.New(slog.NewJSONHandler(io.Discard, nil)) + if args.Log != "" { + file, err := os.OpenFile(args.Log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + return fmt.Errorf("failed to open log file: %w", err) + } + defer file.Close() + + // Create a new logger with a file writer + log = slog.New(slog.NewJSONHandler(file, nil)) + log.Debug("Logging to file", slog.String("file", args.Log)) + } + templStream := jsonrpc2.NewStream(newStdRwc(log, "templStream", stdout, stdin)) + return run(ctx, log, templStream, args) +} + +func run(ctx context.Context, log *slog.Logger, templStream jsonrpc2.Stream, args Arguments) (err error) { + log.Info("lsp: starting up...") + defer func() { + if r := recover(); r != nil { + log.Error("handled panic", slog.Any("recovered", r)) + } + }() + + log.Info("lsp: starting gopls...") + rwc, err := pls.NewGopls(ctx, log, pls.Options{ + Log: args.GoplsLog, + RPCTrace: args.GoplsRPCTrace, + }) + if err != nil { + log.Error("failed to start gopls", slog.Any("error", err)) + os.Exit(1) + } + + cache := proxy.NewSourceMapCache() + diagnosticCache := proxy.NewDiagnosticCache() + + log.Info("creating gopls client") + clientProxy, clientInit := proxy.NewClient(log, cache, diagnosticCache) + _, goplsConn, goplsServer := protocol.NewClient(ctx, clientProxy, jsonrpc2.NewStream(rwc), log) + defer goplsConn.Close() + + log.Info("creating proxy") + // Create the proxy to sit between. + serverProxy := proxy.NewServer(log, goplsServer, cache, diagnosticCache) + + // Create templ server. + log.Info("creating templ server") + _, templConn, templClient := protocol.NewServer(context.Background(), serverProxy, templStream, log) + defer templConn.Close() + + // Allow both the server and the client to initiate outbound requests. + clientInit(templClient) + + // Start the web server if required. + if args.HTTPDebug != "" { + log.Info("starting debug http server", slog.String("addr", args.HTTPDebug)) + h := httpdebug.NewHandler(log, serverProxy) + go func() { + if err := http.ListenAndServe(args.HTTPDebug, h); err != nil { + log.Error("web server failed", slog.Any("error", err)) + } + }() + } + + log.Info("listening") + + select { + case <-ctx.Done(): + log.Info("context closed") + case <-templConn.Done(): + log.Info("templConn closed") + case <-goplsConn.Done(): + log.Info("goplsConn closed") + } + log.Info("shutdown complete") + return +} diff --git a/templ/cmd/templ/lspcmd/pls/main.go b/templ/cmd/templ/lspcmd/pls/main.go new file mode 100644 index 0000000..4f80c24 --- /dev/null +++ b/templ/cmd/templ/lspcmd/pls/main.go @@ -0,0 +1,124 @@ +package pls + +import ( + "context" + "errors" + "fmt" + "io" + "log/slog" + "os" + "os/exec" + "path" + "runtime" +) + +// Options for the gopls client. +type Options struct { + Log string + RPCTrace bool +} + +// AsArguments converts the options into command line arguments for gopls. +func (opts Options) AsArguments() []string { + var args []string + if opts.Log != "" { + args = append(args, "-logfile", opts.Log) + } + if opts.RPCTrace { + args = append(args, "-rpc.trace") + } + return args +} + +func FindGopls() (location string, err error) { + executableName := "gopls" + if runtime.GOOS == "windows" { + executableName = "gopls.exe" + } + + pathLocation, err := exec.LookPath(executableName) + if err == nil { + // Found on the path. + return pathLocation, nil + } + // Unexpected error. + if !errors.Is(err, exec.ErrNotFound) { + return "", fmt.Errorf("unexpected error looking for gopls: %w", err) + } + + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("unexpected error looking for gopls: %w", err) + } + + // Probe standard locations. + locations := []string{ + path.Join(home, "go", "bin", executableName), + path.Join(home, ".local", "bin", executableName), + } + for _, location := range locations { + _, err = os.Stat(location) + if err != nil { + continue + } + // Found in a standard location. + return location, nil + } + + return "", fmt.Errorf("cannot find gopls on the path (%q), in $HOME/go/bin or $HOME/.local/bin/gopls. You can install gopls with `go install golang.org/x/tools/gopls@latest`", os.Getenv("PATH")) +} + +// NewGopls starts gopls and opens up a jsonrpc2 connection to it. +func NewGopls(ctx context.Context, log *slog.Logger, opts Options) (rwc io.ReadWriteCloser, err error) { + location, err := FindGopls() + if err != nil { + return nil, err + } + cmd := exec.Command(location, opts.AsArguments()...) + return newProcessReadWriteCloser(log, cmd) +} + +// newProcessReadWriteCloser creates a processReadWriteCloser to allow stdin/stdout to be used as +// a JSON RPC 2.0 transport. +func newProcessReadWriteCloser(logger *slog.Logger, cmd *exec.Cmd) (rwc processReadWriteCloser, err error) { + stdin, err := cmd.StdinPipe() + if err != nil { + return + } + stdout, err := cmd.StdoutPipe() + if err != nil { + return + } + rwc = processReadWriteCloser{ + in: stdin, + out: stdout, + } + go func() { + if err := cmd.Run(); err != nil { + logger.Error("gopls command error", slog.Any("error", err)) + } + }() + return +} + +type processReadWriteCloser struct { + in io.WriteCloser + out io.ReadCloser +} + +func (prwc processReadWriteCloser) Read(p []byte) (n int, err error) { + return prwc.out.Read(p) +} + +func (prwc processReadWriteCloser) Write(p []byte) (n int, err error) { + return prwc.in.Write(p) +} + +func (prwc processReadWriteCloser) Close() error { + errInClose := prwc.in.Close() + errOutClose := prwc.out.Close() + if errInClose != nil || errOutClose != nil { + return fmt.Errorf("error closing process - in: %v, out: %v", errInClose, errOutClose) + } + return nil +} diff --git a/templ/cmd/templ/lspcmd/proxy/client.go b/templ/cmd/templ/lspcmd/proxy/client.go new file mode 100644 index 0000000..e710dad --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/client.go @@ -0,0 +1,143 @@ +package proxy + +import ( + "context" + "fmt" + "log/slog" + "strings" + + lsp "github.com/a-h/templ/lsp/protocol" +) + +// Client is responsible for rewriting messages that are +// originated from gopls, and are sent to the client. +// +// Since `gopls` is working on Go files, and this is the `templ` LSP, +// the job of this code is to rewrite incoming requests to adjust the +// file name from `*_templ.go` to `*.templ`, and to remap the char +// positions where required. +type Client struct { + Log *slog.Logger + Target lsp.Client + SourceMapCache *SourceMapCache + DiagnosticCache *DiagnosticCache +} + +func NewClient(log *slog.Logger, cache *SourceMapCache, diagnosticCache *DiagnosticCache) (c *Client, init func(lsp.Client)) { + c = &Client{ + Log: log, + SourceMapCache: cache, + DiagnosticCache: diagnosticCache, + } + return c, func(target lsp.Client) { + c.Target = target + } +} + +func (p Client) Progress(ctx context.Context, params *lsp.ProgressParams) (err error) { + p.Log.Info("client <- server: Progress") + return p.Target.Progress(ctx, params) +} +func (p Client) WorkDoneProgressCreate(ctx context.Context, params *lsp.WorkDoneProgressCreateParams) (err error) { + p.Log.Info("client <- server: WorkDoneProgressCreate") + return p.Target.WorkDoneProgressCreate(ctx, params) +} + +func (p Client) LogMessage(ctx context.Context, params *lsp.LogMessageParams) (err error) { + p.Log.Info("client <- server: LogMessage", slog.String("message", params.Message)) + return p.Target.LogMessage(ctx, params) +} + +func (p Client) PublishDiagnostics(ctx context.Context, params *lsp.PublishDiagnosticsParams) (err error) { + p.Log.Info("client <- server: PublishDiagnostics") + if strings.HasSuffix(string(params.URI), "go.mod") { + p.Log.Info("client <- server: PublishDiagnostics: skipping go.mod diagnostics") + return nil + } + // Log diagnostics. + for i, diagnostic := range params.Diagnostics { + p.Log.Info(fmt.Sprintf("client <- server: PublishDiagnostics: [%d]", i), slog.Any("diagnostic", diagnostic)) + } + // Get the sourcemap from the cache. + uri := strings.TrimSuffix(string(params.URI), "_templ.go") + ".templ" + sourceMap, ok := p.SourceMapCache.Get(uri) + if !ok { + p.Log.Error("unable to complete because the sourcemap for the URI doesn't exist in the cache", slog.String("uri", uri)) + return fmt.Errorf("unable to complete because the sourcemap for %q doesn't exist in the cache, has the didOpen notification been sent yet?", uri) + } + params.URI = lsp.DocumentURI(uri) + // Rewrite the positions. + for i := 0; i < len(params.Diagnostics); i++ { + item := params.Diagnostics[i] + start, ok := sourceMap.SourcePositionFromTarget(item.Range.Start.Line, item.Range.Start.Character) + if !ok { + continue + } + if item.Range.Start.Line == item.Range.End.Line { + length := item.Range.End.Character - item.Range.Start.Character + item.Range.Start.Line = start.Line + item.Range.Start.Character = start.Col + item.Range.End.Line = start.Line + item.Range.End.Character = start.Col + length + params.Diagnostics[i] = item + p.Log.Info(fmt.Sprintf("diagnostic [%d] rewritten", i), slog.Any("diagnostic", item)) + continue + } + end, ok := sourceMap.SourcePositionFromTarget(item.Range.End.Line, item.Range.End.Character) + if !ok { + continue + } + item.Range.Start.Line = start.Line + item.Range.Start.Character = start.Col + item.Range.End.Line = end.Line + item.Range.End.Character = end.Col + params.Diagnostics[i] = item + p.Log.Info(fmt.Sprintf("diagnostic [%d] rewritten", i), slog.Any("diagnostic", item)) + } + params.Diagnostics = p.DiagnosticCache.AddTemplDiagnostics(uri, params.Diagnostics) + err = p.Target.PublishDiagnostics(ctx, params) + return err +} + +func (p Client) ShowMessage(ctx context.Context, params *lsp.ShowMessageParams) (err error) { + p.Log.Info("client <- server: ShowMessage", slog.String("message", params.Message)) + if strings.HasPrefix(params.Message, "Do not edit this file!") { + return + } + return p.Target.ShowMessage(ctx, params) +} + +func (p Client) ShowMessageRequest(ctx context.Context, params *lsp.ShowMessageRequestParams) (result *lsp.MessageActionItem, err error) { + p.Log.Info("client <- server: ShowMessageRequest", slog.String("message", params.Message)) + return p.Target.ShowMessageRequest(ctx, params) +} + +func (p Client) Telemetry(ctx context.Context, params any) (err error) { + p.Log.Info("client <- server: Telemetry") + return p.Target.Telemetry(ctx, params) +} + +func (p Client) RegisterCapability(ctx context.Context, params *lsp.RegistrationParams) (err error) { + p.Log.Info("client <- server: RegisterCapability") + return p.Target.RegisterCapability(ctx, params) +} + +func (p Client) UnregisterCapability(ctx context.Context, params *lsp.UnregistrationParams) (err error) { + p.Log.Info("client <- server: UnregisterCapability") + return p.Target.UnregisterCapability(ctx, params) +} + +func (p Client) ApplyEdit(ctx context.Context, params *lsp.ApplyWorkspaceEditParams) (result *lsp.ApplyWorkspaceEditResponse, err error) { + p.Log.Info("client <- server: ApplyEdit") + return p.Target.ApplyEdit(ctx, params) +} + +func (p Client) Configuration(ctx context.Context, params *lsp.ConfigurationParams) (result []any, err error) { + p.Log.Info("client <- server: Configuration") + return p.Target.Configuration(ctx, params) +} + +func (p Client) WorkspaceFolders(ctx context.Context) (result []lsp.WorkspaceFolder, err error) { + p.Log.Info("client <- server: WorkspaceFolders") + return p.Target.WorkspaceFolders(ctx) +} diff --git a/templ/cmd/templ/lspcmd/proxy/diagnosticcache.go b/templ/cmd/templ/lspcmd/proxy/diagnosticcache.go new file mode 100644 index 0000000..9af985b --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/diagnosticcache.go @@ -0,0 +1,61 @@ +package proxy + +import ( + "sync" + + lsp "github.com/a-h/templ/lsp/protocol" +) + +func NewDiagnosticCache() *DiagnosticCache { + return &DiagnosticCache{ + m: &sync.Mutex{}, + cache: make(map[string]fileDiagnostic), + } +} + +type fileDiagnostic struct { + templDiagnostics []lsp.Diagnostic + goplsDiagnostics []lsp.Diagnostic +} + +type DiagnosticCache struct { + m *sync.Mutex + cache map[string]fileDiagnostic +} + +func zeroLengthSliceIfNil(diags []lsp.Diagnostic) []lsp.Diagnostic { + if diags == nil { + return make([]lsp.Diagnostic, 0) + } + return diags +} + +func (dc *DiagnosticCache) AddTemplDiagnostics(uri string, goDiagnostics []lsp.Diagnostic) []lsp.Diagnostic { + goDiagnostics = zeroLengthSliceIfNil(goDiagnostics) + dc.m.Lock() + defer dc.m.Unlock() + diag := dc.cache[uri] + diag.goplsDiagnostics = goDiagnostics + diag.templDiagnostics = zeroLengthSliceIfNil(diag.templDiagnostics) + dc.cache[uri] = diag + return append(diag.templDiagnostics, goDiagnostics...) +} + +func (dc *DiagnosticCache) ClearTemplDiagnostics(uri string) { + dc.m.Lock() + defer dc.m.Unlock() + diag := dc.cache[uri] + diag.templDiagnostics = make([]lsp.Diagnostic, 0) + dc.cache[uri] = diag +} + +func (dc *DiagnosticCache) AddGoDiagnostics(uri string, templDiagnostics []lsp.Diagnostic) []lsp.Diagnostic { + templDiagnostics = zeroLengthSliceIfNil(templDiagnostics) + dc.m.Lock() + defer dc.m.Unlock() + diag := dc.cache[uri] + diag.templDiagnostics = templDiagnostics + diag.goplsDiagnostics = zeroLengthSliceIfNil(diag.goplsDiagnostics) + dc.cache[uri] = diag + return append(diag.goplsDiagnostics, templDiagnostics...) +} diff --git a/templ/cmd/templ/lspcmd/proxy/documentcontents.go b/templ/cmd/templ/lspcmd/proxy/documentcontents.go new file mode 100644 index 0000000..07819ab --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/documentcontents.go @@ -0,0 +1,215 @@ +package proxy + +import ( + "fmt" + "log/slog" + "strings" + "sync" + + lsp "github.com/a-h/templ/lsp/protocol" +) + +// newDocumentContents creates a document content processing tool. +func newDocumentContents(log *slog.Logger) *DocumentContents { + return &DocumentContents{ + m: new(sync.Mutex), + uriToContents: make(map[string]*Document), + log: log, + } +} + +type DocumentContents struct { + m *sync.Mutex + uriToContents map[string]*Document + log *slog.Logger +} + +// Set the contents of a document. +func (dc *DocumentContents) Set(uri string, d *Document) { + dc.m.Lock() + defer dc.m.Unlock() + dc.uriToContents[uri] = d +} + +// Get the contents of a document. +func (dc *DocumentContents) Get(uri string) (d *Document, ok bool) { + dc.m.Lock() + defer dc.m.Unlock() + d, ok = dc.uriToContents[uri] + return +} + +// Delete a document from memory. +func (dc *DocumentContents) Delete(uri string) { + dc.m.Lock() + defer dc.m.Unlock() + delete(dc.uriToContents, uri) +} + +func (dc *DocumentContents) URIs() (uris []string) { + dc.m.Lock() + defer dc.m.Unlock() + uris = make([]string, len(dc.uriToContents)) + var i int + for k := range dc.uriToContents { + uris[i] = k + i++ + } + return uris +} + +// Apply changes to the document from the client, and return a list of change requests to send back to the client. +func (dc *DocumentContents) Apply(uri string, changes []lsp.TextDocumentContentChangeEvent) (d *Document, err error) { + dc.m.Lock() + defer dc.m.Unlock() + var ok bool + d, ok = dc.uriToContents[uri] + if !ok { + err = fmt.Errorf("document not found") + return + } + for _, change := range changes { + d.Apply(change.Range, change.Text) + } + return +} + +func NewDocument(log *slog.Logger, s string) *Document { + return &Document{ + Log: log, + Lines: strings.Split(s, "\n"), + } +} + +type Document struct { + Log *slog.Logger + Lines []string +} + +func (d *Document) LineLengths() (lens []int) { + lens = make([]int, len(d.Lines)) + for i, l := range d.Lines { + lens[i] = len(l) + } + return +} + +func (d *Document) Len() (line, col int) { + line = len(d.Lines) + col = len(d.Lines[len(d.Lines)-1]) + return +} + +func (d *Document) Overwrite(fromLine, fromCol, toLine, toCol int, lines []string) { + suffix := d.Lines[toLine][toCol:] + toLen := d.LineLengths()[toLine] + d.Delete(fromLine, fromCol, toLine, toLen) + lines[len(lines)-1] = lines[len(lines)-1] + suffix + d.Insert(fromLine, fromCol, lines) +} + +func (d *Document) Insert(line, col int, lines []string) { + prefix := d.Lines[line][:col] + suffix := d.Lines[line][col:] + lines[0] = prefix + lines[0] + d.Lines[line] = lines[0] + + if len(lines) > 1 { + d.InsertLines(line+1, lines[1:]) + } + + d.Lines[line+len(lines)-1] = lines[len(lines)-1] + suffix +} + +func (d *Document) InsertLines(i int, withLines []string) { + d.Lines = append(d.Lines[:i], append(withLines, d.Lines[i:]...)...) +} + +func (d *Document) Delete(fromLine, fromCol, toLine, toCol int) { + prefix := d.Lines[fromLine][:fromCol] + suffix := d.Lines[toLine][toCol:] + + // Delete intermediate lines. + deleteFrom := fromLine + deleteTo := fromLine + (toLine - fromLine) + d.DeleteLines(deleteFrom, deleteTo) + + // Merge the contents of the final line. + d.Lines[fromLine] = prefix + suffix +} + +func (d *Document) DeleteLines(i, j int) { + d.Lines = append(d.Lines[:i], d.Lines[j:]...) +} + +func (d *Document) String() string { + return strings.Join(d.Lines, "\n") +} + +func (d *Document) Replace(with string) { + d.Lines = strings.Split(with, "\n") +} + +func (d *Document) Apply(r *lsp.Range, with string) { + withLines := strings.Split(with, "\n") + d.normalize(r) + if d.isWholeDocument(r) { + d.Lines = withLines + return + } + if d.isInsert(r, with) { + d.Insert(int(r.Start.Line), int(r.Start.Character), withLines) + return + } + if d.isDelete(r, with) { + d.Delete(int(r.Start.Line), int(r.Start.Character), int(r.End.Line), int(r.End.Character)) + return + } + if d.isOverwrite(r, with) { + d.Overwrite(int(r.Start.Line), int(r.Start.Character), int(r.End.Line), int(r.End.Character), withLines) + } +} + +func (d *Document) normalize(r *lsp.Range) { + if r == nil { + return + } + lens := d.LineLengths() + if r.Start.Line >= uint32(len(lens)) { + r.Start.Line = uint32(len(lens) - 1) + r.Start.Character = uint32(lens[r.Start.Line]) + } + if r.Start.Character > uint32(lens[r.Start.Line]) { + r.Start.Character = uint32(lens[r.Start.Line]) + } + if r.End.Line >= uint32(len(lens)) { + r.End.Line = uint32(len(lens) - 1) + r.End.Character = uint32(lens[r.End.Line]) + } + if r.End.Character > uint32(lens[r.End.Line]) { + r.End.Character = uint32(lens[r.End.Line]) + } +} + +func (d *Document) isOverwrite(r *lsp.Range, with string) bool { + return (r.End.Line != r.Start.Line || r.Start.Character != r.End.Character) && with != "" +} + +func (d *Document) isInsert(r *lsp.Range, with string) bool { + return r.End.Line == r.Start.Line && r.Start.Character == r.End.Character && with != "" +} + +func (d *Document) isDelete(r *lsp.Range, with string) bool { + return (r.End.Line != r.Start.Line || r.Start.Character != r.End.Character) && with == "" +} + +func (d *Document) isWholeDocument(r *lsp.Range) bool { + if r == nil { + return true + } + if r.Start.Line != 0 || r.Start.Character != 0 { + return false + } + l, c := d.Len() + return r.End.Line == uint32(l) || r.End.Character == uint32(c) +} diff --git a/templ/cmd/templ/lspcmd/proxy/documentcontents_test.go b/templ/cmd/templ/lspcmd/proxy/documentcontents_test.go new file mode 100644 index 0000000..0fd9985 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/documentcontents_test.go @@ -0,0 +1,571 @@ +package proxy + +import ( + "log/slog" + "os" + "testing" + + lsp "github.com/a-h/templ/lsp/protocol" + "github.com/google/go-cmp/cmp" +) + +func TestDocument(t *testing.T) { + tests := []struct { + name string + start string + operations []func(d *Document) + expected string + }{ + { + name: "Replace all content if the range is nil", + start: "0\n1\n2", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(nil, "replaced") + }, + }, + expected: "replaced", + }, + { + name: "If the range matches the length of the file, all of it is replaced", + start: "0\n1\n2", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 1, + }, + }, "replaced") + }, + }, + expected: "replaced", + }, + { + name: "Can insert new text", + start: ``, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 0, + }, + }, "abc") + }, + }, + expected: "abc", + }, + { + name: "Can insert new text that ends with a newline", + start: ``, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 0, + }, + }, "abc\n") + }, + }, + expected: `abc +`, + }, + { + name: "Can insert a new line at the end of existing text", + start: `abc +`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 3, + }, + End: lsp.Position{ + Line: 0, + Character: 3, + }, + }, "\n") + }, + }, + expected: `abc + +`, + }, + { + name: "Can insert a word at the start of existing text", + start: `bc`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 0, + }, + }, "a") + }, + }, + expected: `abc`, + }, + { + name: "Can remove whole line", + start: "0\n1\n2", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 0, + }, + }, "") + }, + }, + expected: "0\n2", + }, + { + name: "Can remove line prefix", + start: "abcdef", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 3, + }, + }, "") + }, + }, + expected: "def", + }, + { + name: "Can remove line substring", + start: "abcdef", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 2, + }, + End: lsp.Position{ + Line: 0, + Character: 3, + }, + }, "") + }, + }, + expected: "abdef", + }, + { + name: "Can remove line suffix", + start: "abcdef", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 4, + }, + End: lsp.Position{ + Line: 0, + Character: 6, + }, + }, "") + }, + }, + expected: "abcd", + }, + { + name: "Can remove across lines", + start: "0\n1\n22", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 1, + }, + }, "") + }, + }, + expected: "0\n2", + }, + { + name: "Can remove part of two lines", + start: "Line one\nLine two\nLine three", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 4, + }, + End: lsp.Position{ + Line: 2, + Character: 4, + }, + }, "") + }, + }, + expected: "Line three", + }, + { + name: "Can remove all lines", + start: "0\n1\n2", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 1, + }, + }, "") + }, + }, + expected: "", + }, + { + name: "Can replace line prefix", + start: "012345", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 3, + }, + }, "ABCDEFG") + }, + }, + expected: "ABCDEFG345", + }, + { + name: "Can replace text across line boundaries", + start: "Line one\nLine two\nLine three", + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 4, + }, + End: lsp.Position{ + Line: 2, + Character: 4, + }, + }, " one test\nNew Line 2\nNew line") + }, + }, + expected: "Line one test\nNew Line 2\nNew line three", + }, + { + name: "Can add new line to end of single line", + start: `a`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 1, + }, + End: lsp.Position{ + Line: 0, + Character: 1, + }, + }, "\nb") + }, + }, + expected: "a\nb", + }, + { + name: "Exceeding the col and line count rounds down to the end of the file", + start: `a`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 200, + Character: 600, + }, + End: lsp.Position{ + Line: 300, + Character: 1200, + }, + }, "\nb") + }, + }, + expected: "a\nb", + }, + { + name: "Can remove a line and add it back from the end of the previous line (insert)", + start: "a\nb\nc", + operations: []func(d *Document){ + func(d *Document) { + // Delete. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 0, + }, + }, "") + // Put it back. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 1, + }, + End: lsp.Position{ + Line: 0, + Character: 1, + }, + }, "\nb") + }, + }, + expected: "a\nb\nc", + }, + { + name: "Can remove a line and add it back from the end of the previous line (overwrite)", + start: "a\nb\nc", + operations: []func(d *Document){ + func(d *Document) { + // Delete. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 0, + }, + }, "") + // Put it back. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 1, + }, + End: lsp.Position{ + Line: 1, + Character: 0, + }, + }, "\nb\n") + }, + }, + expected: "a\nb\nc", + }, + { + name: "Add new line with indent to the end of the line", + // Based on log entry. + // {"level":"info","ts":"2022-06-04T20:55:15+01:00","caller":"proxy/server.go:391","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/adrian/github.com/a-h/templ/generator/test-call/template.templ","version":2},"contentChanges":[{"range":{"start":{"line":4,"character":21},"end":{"line":4,"character":21}},"text":"\n\t\t"}]}} + start: `package testcall + +templ personTemplate(p person) { +
+

{ p.name }

+
+} +`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 4, + Character: 21, + }, + End: lsp.Position{ + Line: 4, + Character: 21, + }, + }, "\n\t\t") + }, + }, + expected: `package testcall + +templ personTemplate(p person) { +
+

{ p.name }

+ +
+} +`, + }, + { + name: "Recreate error smaller", + // Based on log entry. + // {"level":"info","ts":"2022-06-04T20:55:15+01:00","caller":"proxy/server.go:391","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/adrian/github.com/a-h/templ/generator/test-call/template.templ","version":2},"contentChanges":[{"range":{"start":{"line":4,"character":21},"end":{"line":4,"character":21}},"text":"\n\t\t"}]}} + start: "line1\n\t\tline2\nline3", + operations: []func(d *Document){ + func(d *Document) { + // Remove \t\tline2 + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 0, + }, + }, "") + // Put it back. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 5, + }, + End: lsp.Position{ + Line: 1, + Character: 0, + }, + }, + "\n\t\tline2\n") + }, + }, + expected: "line1\n\t\tline2\nline3", + }, + { + name: "Recreate error", + // Based on log entry. + // {"level":"info","ts":"2022-06-04T20:55:15+01:00","caller":"proxy/server.go:391","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/adrian/github.com/a-h/templ/generator/test-call/template.templ","version":2},"contentChanges":[{"range":{"start":{"line":4,"character":21},"end":{"line":4,"character":21}},"text":"\n\t\t"}]}} + start: `
+
© { fmt.Sprintf("%d", time.Now().Year()) }
+
+} +`, + operations: []func(d *Document){ + func(d *Document) { + // Remove
© { fmt.Sprintf("%d", time.Now().Year()) }
+ d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 2, + Character: 0, + }, + }, "") + // Put it back. + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 38, + }, + End: lsp.Position{ + Line: 1, + Character: 0, + }, + }, + "\n\t\t
© { fmt.Sprintf(\"%d\", time.Now().Year()) }
\n") + }, + }, + expected: `
+
© { fmt.Sprintf("%d", time.Now().Year()) }
+
+} +`, + }, + { + name: "Insert at start of line", + // Based on log entry. + // {"level":"info","ts":"2023-03-25T17:17:38Z","caller":"proxy/server.go:393","msg":"client -> server: DidChange","params":{"textDocument":{"uri":"file:///Users/adrian/github.com/a-h/templ/generator/test-call/template.templ","version":5},"contentChanges":[{"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":0}},"text":"a"}]}} + start: `b`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 0, + Character: 0, + }, + End: lsp.Position{ + Line: 0, + Character: 0, + }, + }, "a") + }, + }, + expected: `ab`, + }, + { + name: "Insert full new line", + start: `a +c +d`, + operations: []func(d *Document){ + func(d *Document) { + d.Apply(&lsp.Range{ + Start: lsp.Position{ + Line: 1, + Character: 0, + }, + End: lsp.Position{ + Line: 1, + Character: 0, + }, + }, "b\n") + }, + }, + expected: `a +b +c +d`, + }, + } + + for _, tt := range tests { + logger := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + t.Run(tt.name, func(t *testing.T) { + d := NewDocument(logger, tt.start) + for _, f := range tt.operations { + f(d) + } + actual := d.String() + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/cmd/templ/lspcmd/proxy/import_test.go b/templ/cmd/templ/lspcmd/proxy/import_test.go new file mode 100644 index 0000000..c31f175 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/import_test.go @@ -0,0 +1,293 @@ +package proxy + +import ( + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestFindLastImport(t *testing.T) { + tests := []struct { + name string + templContents string + packageName string + expected string + }{ + { + name: "if there are no imports, add a single line import", + templContents: `package main + +templ example() { +} +`, + packageName: "strings", + expected: `package main + +import "strings" + +templ example() { +} +`, + }, + { + name: "if there is an existing single-line imports, add one at the end", + templContents: `package main + +import "strings" + +templ example() { +} +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +templ example() { +} +`, + }, + { + name: "if there are multiple existing single-line imports, add one at the end", + templContents: `package main + +import "strings" +import "fmt" + +templ example() { +} +`, + packageName: "time", + expected: `package main + +import "strings" +import "fmt" +import "time" + +templ example() { +} +`, + }, + { + name: "if there are existing multi-line imports, add one at the end", + templContents: `package main + +import ( + "strings" +) + +templ example() { +} +`, + packageName: "fmt", + expected: `package main + +import ( + "strings" + "fmt" +) + +templ example() { +} +`, + }, + { + name: "ignore imports that happen after templates", + templContents: `package main + +import "strings" + +templ example() { +} + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +templ example() { +} + +import "other" +`, + }, + { + name: "ignore imports that happen after funcs in the file", + templContents: `package main + +import "strings" + +func example() { +} + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +func example() { +} + +import "other" +`, + }, + { + name: "ignore imports that happen after css expressions in the file", + templContents: `package main + +import "strings" + +css example() { +} + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +css example() { +} + +import "other" +`, + }, + { + name: "ignore imports that happen after script expressions in the file", + templContents: `package main + +import "strings" + +script example() { +} + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +script example() { +} + +import "other" +`, + }, + { + name: "ignore imports that happen after var expressions in the file", + templContents: `package main + +import "strings" + +var s string + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +var s string + +import "other" +`, + }, + { + name: "ignore imports that happen after const expressions in the file", + templContents: `package main + +import "strings" + +const s = "test" + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +const s = "test" + +import "other" +`, + }, + { + name: "ignore imports that happen after type expressions in the file", + templContents: `package main + +import "strings" + +type Value int + +import "other" +`, + packageName: "fmt", + expected: `package main + +import "strings" +import "fmt" + +type Value int + +import "other" +`, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + lines := strings.Split(test.templContents, "\n") + imp := addImport(lines, fmt.Sprintf("%q", test.packageName)) + textWithoutNewline := strings.TrimSuffix(imp.Text, "\n") + actualLines := append(lines[:imp.LineIndex], append([]string{textWithoutNewline}, lines[imp.LineIndex:]...)...) + actual := strings.Join(actualLines, "\n") + if diff := cmp.Diff(test.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestGetPackageFromItemDetail(t *testing.T) { + tests := []struct { + input string + expected string + }{ + { + input: `"fmt"`, + expected: `"fmt"`, + }, + { + input: `func(state fmt.State, verb rune) string (from "fmt")`, + expected: `"fmt"`, + }, + { + input: `non matching`, + expected: `non matching`, + }, + } + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + actual := getPackageFromItemDetail(test.input) + if test.expected != actual { + t.Errorf("expected %q, got %q", test.expected, actual) + } + }) + } +} diff --git a/templ/cmd/templ/lspcmd/proxy/rewrite.go b/templ/cmd/templ/lspcmd/proxy/rewrite.go new file mode 100644 index 0000000..3afb472 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/rewrite.go @@ -0,0 +1,24 @@ +package proxy + +import ( + "path" + "strings" + + lsp "github.com/a-h/templ/lsp/protocol" +) + +func convertTemplToGoURI(templURI lsp.DocumentURI) (isTemplFile bool, goURI lsp.DocumentURI) { + base, fileName := path.Split(string(templURI)) + if !strings.HasSuffix(fileName, ".templ") { + return + } + return true, lsp.DocumentURI(base + (strings.TrimSuffix(fileName, ".templ") + "_templ.go")) +} + +func convertTemplGoToTemplURI(goURI lsp.DocumentURI) (isTemplGoFile bool, templURI lsp.DocumentURI) { + base, fileName := path.Split(string(goURI)) + if !strings.HasSuffix(fileName, "_templ.go") { + return + } + return true, lsp.DocumentURI(base + (strings.TrimSuffix(fileName, "_templ.go") + ".templ")) +} diff --git a/templ/cmd/templ/lspcmd/proxy/server.go b/templ/cmd/templ/lspcmd/proxy/server.go new file mode 100644 index 0000000..651b5c5 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/server.go @@ -0,0 +1,1289 @@ +package proxy + +import ( + "context" + "fmt" + "log/slog" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/a-h/parse" + lsp "github.com/a-h/templ/lsp/protocol" + "github.com/a-h/templ/lsp/uri" + + "github.com/a-h/templ" + "github.com/a-h/templ/cmd/templ/imports" + "github.com/a-h/templ/generator" + "github.com/a-h/templ/parser/v2" +) + +// Server is responsible for rewriting messages that are +// originated from the text editor, and need to be sent to gopls. +// +// Since the editor is working on `templ` files, and `gopls` works +// on Go files, the job of this code is to rewrite incoming requests +// to adjust the file names from `*.templ` to `*_templ.go` and to +// remap the line/character positions in the `templ` files to their +// corresponding locations in the Go file. +// +// This allows gopls to operate as usual. +// +// This code also rewrites the responses back from gopls to do the +// inverse operation - to put the file names back, and readjust any +// character positions. +type Server struct { + Log *slog.Logger + Target lsp.Server + SourceMapCache *SourceMapCache + DiagnosticCache *DiagnosticCache + TemplSource *DocumentContents + GoSource map[string]string + preLoadURIs []*lsp.DidOpenTextDocumentParams +} + +func NewServer(log *slog.Logger, target lsp.Server, cache *SourceMapCache, diagnosticCache *DiagnosticCache) (s *Server) { + return &Server{ + Log: log, + Target: target, + SourceMapCache: cache, + DiagnosticCache: diagnosticCache, + TemplSource: newDocumentContents(log), + GoSource: make(map[string]string), + } +} + +// updatePosition maps positions and filenames from source templ files into the target *.go files. +func (p *Server) updatePosition(templURI lsp.DocumentURI, current lsp.Position) (ok bool, goURI lsp.DocumentURI, updated lsp.Position) { + log := p.Log.With(slog.String("uri", string(templURI))) + var isTemplFile bool + if isTemplFile, goURI = convertTemplToGoURI(templURI); !isTemplFile { + return false, templURI, current + } + sourceMap, ok := p.SourceMapCache.Get(string(templURI)) + if !ok { + log.Warn("completion: sourcemap not found in cache, it could be that didOpen was not called") + return + } + // Map from the source position to target Go position. + to, ok := sourceMap.TargetPositionFromSource(current.Line, current.Character) + if !ok { + log.Info("updatePosition: not found", slog.String("from", fmt.Sprintf("%d:%d", current.Line, current.Character))) + return false, templURI, current + } + log.Info("updatePosition: found", slog.String("fromTempl", fmt.Sprintf("%d:%d", current.Line, current.Character)), + slog.String("toGo", fmt.Sprintf("%d:%d", to.Line, to.Col))) + updated.Line = to.Line + updated.Character = to.Col + + return true, goURI, updated +} + +func (p *Server) convertTemplRangeToGoRange(templURI lsp.DocumentURI, input lsp.Range) (output lsp.Range, ok bool) { + output = input + var sourceMap *parser.SourceMap + sourceMap, ok = p.SourceMapCache.Get(string(templURI)) + if !ok { + p.Log.Warn("templ->go: sourcemap not found in cache") + return + } + // Map from the source position to target Go position. + start, ok := sourceMap.TargetPositionFromSource(input.Start.Line, input.Start.Character) + if ok { + output.Start.Line = start.Line + output.Start.Character = start.Col + } + end, ok := sourceMap.TargetPositionFromSource(input.End.Line, input.End.Character) + if ok { + output.End.Line = end.Line + output.End.Character = end.Col + } + return +} + +func (p *Server) convertGoRangeToTemplRange(templURI lsp.DocumentURI, input lsp.Range) (output lsp.Range) { + output = input + sourceMap, ok := p.SourceMapCache.Get(string(templURI)) + if !ok { + p.Log.Warn("go->templ: sourcemap not found in cache") + return + } + // Map from the source position to target Go position. + start, startPositionMapped := sourceMap.SourcePositionFromTarget(input.Start.Line, input.Start.Character) + if startPositionMapped { + output.Start.Line = start.Line + output.Start.Character = start.Col + } + end, endPositionMapped := sourceMap.SourcePositionFromTarget(input.End.Line, input.End.Character) + if endPositionMapped { + output.End.Line = end.Line + output.End.Character = end.Col + } + if !startPositionMapped || !endPositionMapped { + p.Log.Warn("go->templ: range not found in sourcemap", slog.Any("range", input)) + } + return +} + +// parseTemplate parses the templ file content, and notifies the end user via the LSP about how it went. +func (p *Server) parseTemplate(ctx context.Context, uri uri.URI, templateText string) (template parser.TemplateFile, ok bool, err error) { + template, err = parser.ParseString(templateText) + if err != nil { + msg := &lsp.PublishDiagnosticsParams{ + URI: uri, + Diagnostics: []lsp.Diagnostic{ + { + Severity: lsp.DiagnosticSeverityError, + Code: "", + Source: "templ", + Message: err.Error(), + }, + }, + } + if pe, isParserError := err.(parse.ParseError); isParserError { + msg.Diagnostics[0].Range = lsp.Range{ + Start: lsp.Position{ + Line: uint32(pe.Pos.Line), + Character: uint32(pe.Pos.Col), + }, + End: lsp.Position{ + Line: uint32(pe.Pos.Line), + Character: uint32(pe.Pos.Col), + }, + } + } + msg.Diagnostics = p.DiagnosticCache.AddGoDiagnostics(string(uri), msg.Diagnostics) + err = lsp.ClientFromContext(ctx).PublishDiagnostics(ctx, msg) + if err != nil { + p.Log.Error("failed to publish error diagnostics", slog.Any("error", err)) + } + return + } + template.Filepath = string(uri) + parsedDiagnostics, err := parser.Diagnose(template) + if err != nil { + return + } + ok = true + if len(parsedDiagnostics) > 0 { + msg := &lsp.PublishDiagnosticsParams{ + URI: uri, + } + for _, d := range parsedDiagnostics { + msg.Diagnostics = append(msg.Diagnostics, lsp.Diagnostic{ + Severity: lsp.DiagnosticSeverityWarning, + Code: "", + Source: "templ", + Message: d.Message, + Range: lsp.Range{ + Start: lsp.Position{ + Line: uint32(d.Range.From.Line), + Character: uint32(d.Range.From.Col), + }, + End: lsp.Position{ + Line: uint32(d.Range.To.Line), + Character: uint32(d.Range.To.Col), + }, + }, + }) + } + msg.Diagnostics = p.DiagnosticCache.AddGoDiagnostics(string(uri), msg.Diagnostics) + err = lsp.ClientFromContext(ctx).PublishDiagnostics(ctx, msg) + if err != nil { + p.Log.Error("failed to publish error diagnostics", slog.Any("error", err)) + } + return + } + // Clear templ diagnostics. + p.DiagnosticCache.ClearTemplDiagnostics(string(uri)) + err = lsp.ClientFromContext(ctx).PublishDiagnostics(ctx, &lsp.PublishDiagnosticsParams{ + URI: uri, + // Cannot be nil as per https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#publishDiagnosticsParams + Diagnostics: []lsp.Diagnostic{}, + }) + if err != nil { + p.Log.Error("failed to publish diagnostics", slog.Any("error", err)) + return + } + return +} + +func (p *Server) Initialize(ctx context.Context, params *lsp.InitializeParams) (result *lsp.InitializeResult, err error) { + p.Log.Info("client -> server: Initialize") + defer p.Log.Info("client -> server: Initialize end") + result, err = p.Target.Initialize(ctx, params) + if err != nil { + p.Log.Error("Initialize failed", slog.Any("error", err)) + } + // Add the '<' and '{' trigger so that we can do snippets for tags. + if result.Capabilities.CompletionProvider == nil { + result.Capabilities.CompletionProvider = &lsp.CompletionOptions{} + } + result.Capabilities.CompletionProvider.TriggerCharacters = append(result.Capabilities.CompletionProvider.TriggerCharacters, "{", "<") + // Remove all the gopls commands. + if result.Capabilities.ExecuteCommandProvider == nil { + result.Capabilities.ExecuteCommandProvider = &lsp.ExecuteCommandOptions{} + } + result.Capabilities.ExecuteCommandProvider.Commands = []string{} + result.Capabilities.DocumentFormattingProvider = true + result.Capabilities.SemanticTokensProvider = nil + result.Capabilities.DocumentRangeFormattingProvider = false + result.Capabilities.TextDocumentSync = lsp.TextDocumentSyncOptions{ + OpenClose: true, + Change: lsp.TextDocumentSyncKindFull, + WillSave: false, + WillSaveWaitUntil: false, + Save: &lsp.SaveOptions{IncludeText: true}, + } + + for _, c := range params.WorkspaceFolders { + path := strings.TrimPrefix(c.URI, "file://") + werr := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + p.Log.Info("found file", slog.String("path", path)) + uri := uri.URI("file://" + path) + isTemplFile, goURI := convertTemplToGoURI(uri) + + if !isTemplFile { + return nil + } + + b, err := os.ReadFile(path) + if err != nil { + return err + } + p.TemplSource.Set(string(uri), NewDocument(p.Log, string(b))) + // Parse the template. + template, ok, err := p.parseTemplate(ctx, uri, string(b)) + if err != nil { + p.Log.Error("parseTemplate failure", slog.Any("error", err)) + } + if !ok { + p.Log.Info("parsing template did not succeed", slog.String("uri", string(uri))) + return nil + } + w := new(strings.Builder) + generatorOutput, err := generator.Generate(template, w) + if err != nil { + return fmt.Errorf("generate failure: %w", err) + } + p.Log.Info("setting source map cache contents", slog.String("uri", string(uri))) + p.SourceMapCache.Set(string(uri), generatorOutput.SourceMap) + // Set the Go contents. + p.GoSource[string(uri)] = w.String() + + didOpenParams := &lsp.DidOpenTextDocumentParams{ + TextDocument: lsp.TextDocumentItem{ + URI: goURI, + Text: w.String(), + Version: 1, + LanguageID: "go", + }, + } + + p.preLoadURIs = append(p.preLoadURIs, didOpenParams) + return nil + }) + if werr != nil { + p.Log.Error("walk error", slog.Any("error", werr)) + } + } + + result.ServerInfo.Name = "templ-lsp" + result.ServerInfo.Version = templ.Version() + + return result, err +} + +func (p *Server) Initialized(ctx context.Context, params *lsp.InitializedParams) (err error) { + p.Log.Info("client -> server: Initialized") + defer p.Log.Info("client -> server: Initialized end") + goInitErr := p.Target.Initialized(ctx, params) + + for i, doParams := range p.preLoadURIs { + doErr := p.Target.DidOpen(ctx, doParams) + if doErr != nil { + return doErr + } + p.preLoadURIs[i] = nil + } + + return goInitErr +} + +func (p *Server) Shutdown(ctx context.Context) (err error) { + p.Log.Info("client -> server: Shutdown") + defer p.Log.Info("client -> server: Shutdown end") + return p.Target.Shutdown(ctx) +} + +func (p *Server) Exit(ctx context.Context) (err error) { + p.Log.Info("client -> server: Exit") + defer p.Log.Info("client -> server: Exit end") + return p.Target.Exit(ctx) +} + +func (p *Server) WorkDoneProgressCancel(ctx context.Context, params *lsp.WorkDoneProgressCancelParams) (err error) { + p.Log.Info("client -> server: WorkDoneProgressCancel") + defer p.Log.Info("client -> server: WorkDoneProgressCancel end") + return p.Target.WorkDoneProgressCancel(ctx, params) +} + +func (p *Server) LogTrace(ctx context.Context, params *lsp.LogTraceParams) (err error) { + p.Log.Info("client -> server: LogTrace", slog.String("message", params.Message)) + defer p.Log.Info("client -> server: LogTrace end") + return p.Target.LogTrace(ctx, params) +} + +func (p *Server) SetTrace(ctx context.Context, params *lsp.SetTraceParams) (err error) { + p.Log.Info("client -> server: SetTrace") + defer p.Log.Info("client -> server: SetTrace end") + return p.Target.SetTrace(ctx, params) +} + +var supportedCodeActions = map[string]bool{} + +func (p *Server) CodeAction(ctx context.Context, params *lsp.CodeActionParams) (result []lsp.CodeAction, err error) { + p.Log.Info("client -> server: CodeAction", slog.Any("params", params)) + defer p.Log.Info("client -> server: CodeAction end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.CodeAction(ctx, params) + } + templURI := params.TextDocument.URI + var ok bool + if params.Range, ok = p.convertTemplRangeToGoRange(templURI, params.Range); !ok { + // Don't pass the request to gopls if the range is not within a Go code block. + return + } + params.TextDocument.URI = goURI + result, err = p.Target.CodeAction(ctx, params) + if err != nil { + return + } + var updatedResults []lsp.CodeAction + // Filter out commands that are not yet supported. + // For example, "Fill Struct" runs the `gopls.apply_fix` command. + // This command has a set of arguments, including Fix, Range and URI. + // However, these are just a map[string]any so for each command that we want to support, + // we need to know what the arguments are so that we can rewrite them. + for i := 0; i < len(result); i++ { + if !supportedCodeActions[result[i].Title] { + continue + } + r := result[i] + // Rewrite the Diagnostics range field. + for di := 0; di < len(r.Diagnostics); di++ { + r.Diagnostics[di].Range = p.convertGoRangeToTemplRange(templURI, r.Diagnostics[di].Range) + } + // Rewrite the DocumentChanges. + if r.Edit != nil { + for dci := 0; dci < len(r.Edit.DocumentChanges); dci++ { + dc := r.Edit.DocumentChanges[0] + for ei := 0; ei < len(dc.Edits); ei++ { + dc.Edits[ei].Range = p.convertGoRangeToTemplRange(templURI, dc.Edits[ei].Range) + } + dc.TextDocument.URI = templURI + r.Edit.DocumentChanges[dci] = dc + } + } + updatedResults = append(updatedResults, r) + } + return updatedResults, nil +} + +func (p *Server) CodeLens(ctx context.Context, params *lsp.CodeLensParams) (result []lsp.CodeLens, err error) { + p.Log.Info("client -> server: CodeLens") + defer p.Log.Info("client -> server: CodeLens end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.CodeLens(ctx, params) + } + templURI := params.TextDocument.URI + params.TextDocument.URI = goURI + result, err = p.Target.CodeLens(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + for i := 0; i < len(result); i++ { + cl := result[i] + cl.Range = p.convertGoRangeToTemplRange(templURI, cl.Range) + result[i] = cl + } + return +} + +func (p *Server) CodeLensResolve(ctx context.Context, params *lsp.CodeLens) (result *lsp.CodeLens, err error) { + p.Log.Info("client -> server: CodeLensResolve") + defer p.Log.Info("client -> server: CodeLensResolve end") + return p.Target.CodeLensResolve(ctx, params) +} + +func (p *Server) ColorPresentation(ctx context.Context, params *lsp.ColorPresentationParams) (result []lsp.ColorPresentation, err error) { + p.Log.Info("client -> server: ColorPresentation ColorPresentation") + defer p.Log.Info("client -> server: ColorPresentation end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.ColorPresentation(ctx, params) + } + templURI := params.TextDocument.URI + params.TextDocument.URI = goURI + result, err = p.Target.ColorPresentation(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + for i := 0; i < len(result); i++ { + r := result[i] + if r.TextEdit != nil { + r.TextEdit.Range = p.convertGoRangeToTemplRange(templURI, r.TextEdit.Range) + } + result[i] = r + } + return +} + +func (p *Server) Completion(ctx context.Context, params *lsp.CompletionParams) (result *lsp.CompletionList, err error) { + p.Log.Info("client -> server: Completion") + defer p.Log.Info("client -> server: Completion end") + if params.Context != nil && params.Context.TriggerCharacter == "<" { + result = &lsp.CompletionList{ + Items: htmlSnippets, + } + return + } + // Get the sourcemap from the cache. + templURI := params.TextDocument.URI + var ok bool + ok, params.TextDocument.URI, params.TextDocumentPositionParams.Position = p.updatePosition(templURI, params.TextDocumentPositionParams.Position) + if !ok { + return nil, nil + } + + // Ensure that Go source is available. + gosrc := strings.Split(p.GoSource[string(templURI)], "\n") + if len(gosrc) < int(params.TextDocumentPositionParams.Position.Line) { + p.Log.Info("completion: line position out of range") + return nil, nil + } + if len(gosrc[params.TextDocumentPositionParams.Position.Line]) < int(params.TextDocumentPositionParams.Position.Character) { + p.Log.Info("completion: col position out of range") + return nil, nil + } + + // Call the target. + result, err = p.Target.Completion(ctx, params) + if err != nil { + p.Log.Warn("completion: got gopls error", slog.Any("error", err)) + return + } + if result == nil { + return + } + // Rewrite the result positions. + p.Log.Info("completion: received items", slog.Int("count", len(result.Items))) + + for i := 0; i < len(result.Items); i++ { + item := result.Items[i] + if item.TextEdit != nil { + if item.TextEdit.TextEdit != nil { + item.TextEdit.TextEdit.Range = p.convertGoRangeToTemplRange(templURI, item.TextEdit.TextEdit.Range) + } + if item.TextEdit.InsertReplaceEdit != nil { + item.TextEdit.InsertReplaceEdit.Insert = p.convertGoRangeToTemplRange(templURI, item.TextEdit.InsertReplaceEdit.Insert) + item.TextEdit.InsertReplaceEdit.Replace = p.convertGoRangeToTemplRange(templURI, item.TextEdit.InsertReplaceEdit.Replace) + } + } + if len(item.AdditionalTextEdits) > 0 { + doc, ok := p.TemplSource.Get(string(templURI)) + if !ok { + continue + } + pkg := getPackageFromItemDetail(item.Detail) + imp := addImport(doc.Lines, pkg) + item.AdditionalTextEdits = []lsp.TextEdit{ + { + Range: lsp.Range{ + Start: lsp.Position{Line: uint32(imp.LineIndex), Character: 0}, + End: lsp.Position{Line: uint32(imp.LineIndex), Character: 0}, + }, + NewText: imp.Text, + }, + } + } + result.Items[i] = item + } + + // Add templ snippet. + result.Items = append(result.Items, snippet...) + + return +} + +var completionWithImport = regexp.MustCompile(`^.*\(from\s(".+")\)$`) + +func getPackageFromItemDetail(pkg string) string { + if m := completionWithImport.FindStringSubmatch(pkg); len(m) == 2 { + return m[1] + } + return pkg +} + +type importInsert struct { + Text string + LineIndex int +} + +var nonImportKeywordRegexp = regexp.MustCompile(`^(?:templ|func|css|script|var|const|type)\s`) + +func addImport(lines []string, pkg string) (result importInsert) { + var isInMultiLineImport bool + lastSingleLineImportIndex := -1 + for lineIndex, line := range lines { + if strings.HasPrefix(line, "import (") { + isInMultiLineImport = true + continue + } + if strings.HasPrefix(line, "import \"") { + lastSingleLineImportIndex = lineIndex + continue + } + if isInMultiLineImport && strings.HasPrefix(line, ")") { + return importInsert{ + LineIndex: lineIndex, + Text: fmt.Sprintf("\t%s\n", pkg), + } + } + // Only add import statements before templates, functions, css, and script templates. + if nonImportKeywordRegexp.MatchString(line) { + break + } + } + var suffix string + if lastSingleLineImportIndex == -1 { + lastSingleLineImportIndex = 1 + suffix = "\n" + } + return importInsert{ + LineIndex: lastSingleLineImportIndex + 1, + Text: fmt.Sprintf("import %s\n%s", pkg, suffix), + } +} + +func (p *Server) CompletionResolve(ctx context.Context, params *lsp.CompletionItem) (result *lsp.CompletionItem, err error) { + p.Log.Info("client -> server: CompletionResolve") + defer p.Log.Info("client -> server: CompletionResolve end") + return p.Target.CompletionResolve(ctx, params) +} + +func (p *Server) Declaration(ctx context.Context, params *lsp.DeclarationParams) (result []lsp.Location /* Declaration | DeclarationLink[] | null */, err error) { + p.Log.Info("client -> server: Declaration") + defer p.Log.Info("client -> server: Declaration end") + // Rewrite the request. + templURI := params.TextDocument.URI + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(templURI, params.Position) + if !ok { + return nil, nil + } + // Call gopls and get the result. + result, err = p.Target.Declaration(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + for i := 0; i < len(result); i++ { + if isTemplGoFile, templURI := convertTemplGoToTemplURI(result[i].URI); isTemplGoFile { + result[i].URI = templURI + result[i].Range = p.convertGoRangeToTemplRange(templURI, result[i].Range) + } + } + return +} + +func (p *Server) Definition(ctx context.Context, params *lsp.DefinitionParams) (result []lsp.Location /* Definition | DefinitionLink[] | null */, err error) { + p.Log.Info("client -> server: Definition") + defer p.Log.Info("client -> server: Definition end") + // Rewrite the request. + templURI := params.TextDocument.URI + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(templURI, params.Position) + if !ok { + return result, nil + } + // Call gopls and get the result. + result, err = p.Target.Definition(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + for i := 0; i < len(result); i++ { + if isTemplGoFile, templURI := convertTemplGoToTemplURI(result[i].URI); isTemplGoFile { + result[i].URI = templURI + result[i].Range = p.convertGoRangeToTemplRange(templURI, result[i].Range) + } + } + return +} + +func (p *Server) DidChange(ctx context.Context, params *lsp.DidChangeTextDocumentParams) (err error) { + p.Log.Info("client -> server: DidChange", slog.Any("params", params)) + defer p.Log.Info("client -> server: DidChange end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + p.Log.Error("not a templ file") + return + } + // Apply content changes to the cached template. + d, err := p.TemplSource.Apply(string(params.TextDocument.URI), params.ContentChanges) + if err != nil { + p.Log.Error("error applying changes", slog.Any("error", err)) + return + } + // Update the Go code. + p.Log.Info("parsing template") + template, ok, err := p.parseTemplate(ctx, params.TextDocument.URI, d.String()) + if err != nil { + p.Log.Error("parseTemplate failure", slog.Any("error", err)) + } + if !ok { + return + } + w := new(strings.Builder) + // In future updates, we may pass `WithSkipCodeGeneratedComment` to the generator. + // This will enable a number of actions within gopls that it doesn't currently apply because + // it recognises templ code as being auto-generated. + // + // This change would increase the surface area of gopls that we use, so may surface a number of issues + // if enabled. + generatorOutput, err := generator.Generate(template, w) + if err != nil { + p.Log.Error("generate failure", slog.Any("error", err)) + return + } + // Cache the sourcemap. + p.Log.Info("setting cache", slog.String("uri", string(params.TextDocument.URI))) + p.SourceMapCache.Set(string(params.TextDocument.URI), generatorOutput.SourceMap) + p.GoSource[string(params.TextDocument.URI)] = w.String() + // Change the path. + params.TextDocument.URI = goURI + params.TextDocument.TextDocumentIdentifier.URI = goURI + // Overwrite all the Go contents. + params.ContentChanges = []lsp.TextDocumentContentChangeEvent{{ + Text: w.String(), + }} + return p.Target.DidChange(ctx, params) +} + +func (p *Server) DidChangeConfiguration(ctx context.Context, params *lsp.DidChangeConfigurationParams) (err error) { + p.Log.Info("client -> server: DidChangeConfiguration") + defer p.Log.Info("client -> server: DidChangeConfiguration end") + return p.Target.DidChangeConfiguration(ctx, params) +} + +func (p *Server) DidChangeWatchedFiles(ctx context.Context, params *lsp.DidChangeWatchedFilesParams) (err error) { + p.Log.Info("client -> server: DidChangeWatchedFiles") + defer p.Log.Info("client -> server: DidChangeWatchedFiles end") + return p.Target.DidChangeWatchedFiles(ctx, params) +} + +func (p *Server) DidChangeWorkspaceFolders(ctx context.Context, params *lsp.DidChangeWorkspaceFoldersParams) (err error) { + p.Log.Info("client -> server: DidChangeWorkspaceFolders") + defer p.Log.Info("client -> server: DidChangeWorkspaceFolders end") + return p.Target.DidChangeWorkspaceFolders(ctx, params) +} + +func (p *Server) DidClose(ctx context.Context, params *lsp.DidCloseTextDocumentParams) (err error) { + p.Log.Info("client -> server: DidClose") + defer p.Log.Info("client -> server: DidClose end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.DidClose(ctx, params) + } + // Delete the template and sourcemaps from caches. + p.TemplSource.Delete(string(params.TextDocument.URI)) + p.SourceMapCache.Delete(string(params.TextDocument.URI)) + // Get gopls to delete the Go file from its cache. + params.TextDocument.URI = goURI + return p.Target.DidClose(ctx, params) +} + +func (p *Server) DidOpen(ctx context.Context, params *lsp.DidOpenTextDocumentParams) (err error) { + p.Log.Info("client -> server: DidOpen", slog.String("uri", string(params.TextDocument.URI))) + defer p.Log.Info("client -> server: DidOpen end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.DidOpen(ctx, params) + } + // Cache the template doc. + p.TemplSource.Set(string(params.TextDocument.URI), NewDocument(p.Log, params.TextDocument.Text)) + // Parse the template. + template, ok, err := p.parseTemplate(ctx, params.TextDocument.URI, params.TextDocument.Text) + if err != nil { + p.Log.Error("parseTemplate failure", slog.Any("error", err)) + } + if !ok { + p.Log.Info("parsing template did not succeed", slog.String("uri", string(params.TextDocument.URI))) + return nil + } + // Generate the output code and cache the source map and Go contents to use during completion + // requests. + w := new(strings.Builder) + generatorOutput, err := generator.Generate(template, w) + if err != nil { + return + } + p.Log.Info("setting source map cache contents", slog.String("uri", string(params.TextDocument.URI))) + p.SourceMapCache.Set(string(params.TextDocument.URI), generatorOutput.SourceMap) + // Set the Go contents. + params.TextDocument.Text = w.String() + p.GoSource[string(params.TextDocument.URI)] = params.TextDocument.Text + // Change the path. + params.TextDocument.URI = goURI + return p.Target.DidOpen(ctx, params) +} + +func (p *Server) DidSave(ctx context.Context, params *lsp.DidSaveTextDocumentParams) (err error) { + p.Log.Info("client -> server: DidSave") + defer p.Log.Info("client -> server: DidSave end") + if isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI); isTemplFile { + params.TextDocument.URI = goURI + } + return p.Target.DidSave(ctx, params) +} + +func (p *Server) DocumentColor(ctx context.Context, params *lsp.DocumentColorParams) (result []lsp.ColorInformation, err error) { + p.Log.Info("client -> server: DocumentColor") + defer p.Log.Info("client -> server: DocumentColor end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.DocumentColor(ctx, params) + } + templURI := params.TextDocument.URI + params.TextDocument.URI = goURI + result, err = p.Target.DocumentColor(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + for i := 0; i < len(result); i++ { + result[i].Range = p.convertGoRangeToTemplRange(templURI, result[i].Range) + } + return +} + +func (p *Server) DocumentHighlight(ctx context.Context, params *lsp.DocumentHighlightParams) (result []lsp.DocumentHighlight, err error) { + p.Log.Info("client -> server: DocumentHighlight") + defer p.Log.Info("client -> server: DocumentHighlight end") + return +} + +func (p *Server) DocumentLink(ctx context.Context, params *lsp.DocumentLinkParams) (result []lsp.DocumentLink, err error) { + p.Log.Info("client -> server: DocumentLink", slog.String("uri", string(params.TextDocument.URI))) + defer p.Log.Info("client -> server: DocumentLink end") + return +} + +func (p *Server) DocumentLinkResolve(ctx context.Context, params *lsp.DocumentLink) (result *lsp.DocumentLink, err error) { + p.Log.Info("client -> server: DocumentLinkResolve") + defer p.Log.Info("client -> server: DocumentLinkResolve end") + isTemplFile, goURI := convertTemplToGoURI(params.Target) + if !isTemplFile { + return p.Target.DocumentLinkResolve(ctx, params) + } + templURI := params.Target + params.Target = goURI + var ok bool + if params.Range, ok = p.convertTemplRangeToGoRange(templURI, params.Range); !ok { + return + } + // Rewrite the result. + result, err = p.Target.DocumentLinkResolve(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + result.Target = templURI + result.Range = p.convertGoRangeToTemplRange(templURI, result.Range) + return +} + +func (p *Server) DocumentSymbol(ctx context.Context, params *lsp.DocumentSymbolParams) (result []lsp.SymbolInformationOrDocumentSymbol, err error) { + p.Log.Info("client -> server: DocumentSymbol") + defer p.Log.Info("client -> server: DocumentSymbol end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return p.Target.DocumentSymbol(ctx, params) + } + templURI := params.TextDocument.URI + params.TextDocument.URI = goURI + symbols, err := p.Target.DocumentSymbol(ctx, params) + if err != nil { + return nil, err + } + + for _, s := range symbols { + if s.DocumentSymbol != nil { + p.convertSymbolRange(templURI, s.DocumentSymbol) + result = append(result, s) + } + if s.SymbolInformation != nil { + s.SymbolInformation.Location.URI = templURI + s.SymbolInformation.Location.Range = p.convertGoRangeToTemplRange(templURI, s.SymbolInformation.Location.Range) + result = append(result, s) + } + } + + return result, err +} + +func (p *Server) convertSymbolRange(templURI lsp.DocumentURI, s *lsp.DocumentSymbol) { + sourceMap, ok := p.SourceMapCache.Get(string(templURI)) + if !ok { + p.Log.Warn("go->templ: sourcemap not found in cache") + return + } + src, ok := sourceMap.SymbolSourceRangeFromTarget(s.Range.Start.Line, s.Range.Start.Character) + if !ok { + p.Log.Warn("go->templ: symbol range not found", slog.Any("symbol", s), slog.Any("choices", sourceMap.TargetSymbolRangeToSource)) + return + } + s.Range = lsp.Range{ + Start: lsp.Position{ + Line: uint32(src.From.Line), + Character: uint32(src.From.Col), + }, + End: lsp.Position{ + Line: uint32(src.To.Line), + Character: uint32(src.To.Col), + }, + } + // Within the symbol, we can select sub-sections. + // These are Go expressions, in the standard source map. + s.SelectionRange = p.convertGoRangeToTemplRange(templURI, s.SelectionRange) + for i := 0; i < len(s.Children); i++ { + p.convertSymbolRange(templURI, &s.Children[i]) + if !isRangeWithin(s.Range, s.Children[i].Range) { + p.Log.Error("child symbol range not within parent range", slog.Any("symbol", s.Children[i]), slog.Int("index", i)) + } + } + if !isRangeWithin(s.Range, s.SelectionRange) { + p.Log.Error("selection range not within range", slog.Any("symbol", s)) + } +} + +func isRangeWithin(parent, child lsp.Range) bool { + if child.Start.Line < parent.Start.Line || child.End.Line > parent.End.Line { + return false + } + if child.Start.Line == parent.Start.Line && child.Start.Character < parent.Start.Character { + return false + } + if child.End.Line == parent.End.Line && child.End.Character > parent.End.Character { + return false + } + return true +} + +func (p *Server) ExecuteCommand(ctx context.Context, params *lsp.ExecuteCommandParams) (result any, err error) { + p.Log.Info("client -> server: ExecuteCommand") + defer p.Log.Info("client -> server: ExecuteCommand end") + return p.Target.ExecuteCommand(ctx, params) +} + +func (p *Server) FoldingRanges(ctx context.Context, params *lsp.FoldingRangeParams) (result []lsp.FoldingRange, err error) { + p.Log.Info("client -> server: FoldingRanges") + defer p.Log.Info("client -> server: FoldingRanges end") + // There are no folding ranges in templ files. + // return p.Target.FoldingRanges(ctx, params) + return []lsp.FoldingRange{}, nil +} + +func (p *Server) Formatting(ctx context.Context, params *lsp.DocumentFormattingParams) (result []lsp.TextEdit, err error) { + p.Log.Info("client -> server: Formatting") + defer p.Log.Info("client -> server: Formatting end") + // Format the current document. + d, _ := p.TemplSource.Get(string(params.TextDocument.URI)) + template, ok, err := p.parseTemplate(ctx, params.TextDocument.URI, d.String()) + if err != nil { + p.Log.Error("parseTemplate failure", slog.Any("error", err)) + return + } + if !ok { + return + } + p.Log.Info("attempting to organise imports", slog.String("uri", template.Filepath)) + template, err = imports.Process(template) + if err != nil { + p.Log.Error("organise imports failure", slog.Any("error", err)) + return + } + w := new(strings.Builder) + err = template.Write(w) + if err != nil { + p.Log.Error("handleFormatting: faled to write template", slog.Any("error", err)) + return + } + // Replace everything. + result = append(result, lsp.TextEdit{ + Range: lsp.Range{ + Start: lsp.Position{}, + End: lsp.Position{Line: uint32(len(d.Lines)), Character: 0}, + }, + NewText: w.String(), + }) + d.Replace(w.String()) + return +} + +func (p *Server) Hover(ctx context.Context, params *lsp.HoverParams) (result *lsp.Hover, err error) { + p.Log.Info("client -> server: Hover") + defer p.Log.Info("client -> server: Hover end") + // Rewrite the request. + templURI := params.TextDocument.URI + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + // Call gopls. + result, err = p.Target.Hover(ctx, params) + if err != nil { + return + } + // Rewrite the response. + if result != nil && result.Range != nil { + p.Log.Info("hover: result returned") + r := p.convertGoRangeToTemplRange(templURI, *result.Range) + p.Log.Info("hover: setting range") + result.Range = &r + } + return +} + +func (p *Server) Implementation(ctx context.Context, params *lsp.ImplementationParams) (result []lsp.Location, err error) { + p.Log.Info("client -> server: Implementation") + defer p.Log.Info("client -> server: Implementation end") + templURI := params.TextDocument.URI + // Rewrite the request. + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + result, err = p.Target.Implementation(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + // Rewrite the response. + for i := 0; i < len(result); i++ { + r := result[i] + r.URI = templURI + r.Range = p.convertGoRangeToTemplRange(templURI, r.Range) + result[i] = r + } + return +} + +func (p *Server) OnTypeFormatting(ctx context.Context, params *lsp.DocumentOnTypeFormattingParams) (result []lsp.TextEdit, err error) { + p.Log.Info("client -> server: OnTypeFormatting") + defer p.Log.Info("client -> server: OnTypeFormatting end") + templURI := params.TextDocument.URI + // Rewrite the request. + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + // Get the response. + result, err = p.Target.OnTypeFormatting(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + // Rewrite the response. + for i := 0; i < len(result); i++ { + r := result[i] + r.Range = p.convertGoRangeToTemplRange(templURI, r.Range) + result[i] = r + } + return +} + +func (p *Server) PrepareRename(ctx context.Context, params *lsp.PrepareRenameParams) (result *lsp.Range, err error) { + p.Log.Info("client -> server: PrepareRename") + defer p.Log.Info("client -> server: PrepareRename end") + templURI := params.TextDocument.URI + // Rewrite the request. + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + // Get the response. + result, err = p.Target.PrepareRename(ctx, params) + if err != nil { + return + } + if result == nil { + return + } + // Rewrite the response. + output := p.convertGoRangeToTemplRange(templURI, *result) + return &output, nil +} + +func (p *Server) RangeFormatting(ctx context.Context, params *lsp.DocumentRangeFormattingParams) (result []lsp.TextEdit, err error) { + p.Log.Info("client -> server: RangeFormatting") + defer p.Log.Info("client -> server: RangeFormatting end") + templURI := params.TextDocument.URI + // Rewrite the request. + var isTemplURI bool + isTemplURI, params.TextDocument.URI = convertTemplToGoURI(params.TextDocument.URI) + if !isTemplURI { + err = fmt.Errorf("not a templ file") + return + } + // Call gopls. + result, err = p.Target.RangeFormatting(ctx, params) + if err != nil { + return + } + // Rewrite the response. + for i := 0; i < len(result); i++ { + r := result[i] + r.Range = p.convertGoRangeToTemplRange(templURI, r.Range) + result[i] = r + } + return result, err +} + +func (p *Server) References(ctx context.Context, params *lsp.ReferenceParams) (result []lsp.Location, err error) { + p.Log.Info("client -> server: References") + defer p.Log.Info("client -> server: References end") + // Rewrite the request. + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + // Call gopls. + result, err = p.Target.References(ctx, params) + if err != nil { + return + } + // Rewrite the response. + for i := 0; i < len(result); i++ { + r := result[i] + isTemplURI, templURI := convertTemplGoToTemplURI(r.URI) + if isTemplURI { + p.Log.Info(fmt.Sprintf("references-%d - range conversion for %s", i, r.URI)) + r.URI, r.Range = templURI, p.convertGoRangeToTemplRange(templURI, r.Range) + } + p.Log.Info(fmt.Sprintf("references-%d: %+v", i, r)) + result[i] = r + } + return result, err +} + +func (p *Server) Rename(ctx context.Context, params *lsp.RenameParams) (result *lsp.WorkspaceEdit, err error) { + p.Log.Info("client -> server: Rename") + defer p.Log.Info("client -> server: Rename end") + return p.Target.Rename(ctx, params) +} + +func (p *Server) SignatureHelp(ctx context.Context, params *lsp.SignatureHelpParams) (result *lsp.SignatureHelp, err error) { + p.Log.Info("client -> server: SignatureHelp") + defer p.Log.Info("client -> server: SignatureHelp end") + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + return p.Target.SignatureHelp(ctx, params) +} + +func (p *Server) Symbols(ctx context.Context, params *lsp.WorkspaceSymbolParams) (result []lsp.SymbolInformation, err error) { + p.Log.Info("client -> server: Symbols") + defer p.Log.Info("client -> server: Symbols end") + return p.Target.Symbols(ctx, params) +} + +func (p *Server) TypeDefinition(ctx context.Context, params *lsp.TypeDefinitionParams) (result []lsp.Location, err error) { + p.Log.Info("client -> server: TypeDefinition") + defer p.Log.Info("client -> server: TypeDefinition end") + var ok bool + ok, params.TextDocument.URI, params.Position = p.updatePosition(params.TextDocument.URI, params.Position) + if !ok { + return nil, nil + } + return p.Target.TypeDefinition(ctx, params) +} + +func (p *Server) WillSave(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (err error) { + p.Log.Info("client -> server: WillSave") + defer p.Log.Info("client -> server: WillSave end") + var ok bool + ok, params.TextDocument.URI = convertTemplToGoURI(params.TextDocument.URI) + if !ok { + p.Log.Error("not a templ file") + return nil + } + return p.Target.WillSave(ctx, params) +} + +func (p *Server) WillSaveWaitUntil(ctx context.Context, params *lsp.WillSaveTextDocumentParams) (result []lsp.TextEdit, err error) { + p.Log.Info("client -> server: WillSaveWaitUntil") + defer p.Log.Info("client -> server: WillSaveWaitUntil end") + return p.Target.WillSaveWaitUntil(ctx, params) +} + +func (p *Server) ShowDocument(ctx context.Context, params *lsp.ShowDocumentParams) (result *lsp.ShowDocumentResult, err error) { + p.Log.Info("client -> server: ShowDocument") + defer p.Log.Info("client -> server: ShowDocument end") + return p.Target.ShowDocument(ctx, params) +} + +func (p *Server) WillCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (result *lsp.WorkspaceEdit, err error) { + p.Log.Info("client -> server: WillCreateFiles") + defer p.Log.Info("client -> server: WillCreateFiles end") + return p.Target.WillCreateFiles(ctx, params) +} + +func (p *Server) DidCreateFiles(ctx context.Context, params *lsp.CreateFilesParams) (err error) { + p.Log.Info("client -> server: DidCreateFiles") + defer p.Log.Info("client -> server: DidCreateFiles end") + return p.Target.DidCreateFiles(ctx, params) +} + +func (p *Server) WillRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (result *lsp.WorkspaceEdit, err error) { + p.Log.Info("client -> server: WillRenameFiles") + defer p.Log.Info("client -> server: WillRenameFiles end") + return p.Target.WillRenameFiles(ctx, params) +} + +func (p *Server) DidRenameFiles(ctx context.Context, params *lsp.RenameFilesParams) (err error) { + p.Log.Info("client -> server: DidRenameFiles") + defer p.Log.Info("client -> server: DidRenameFiles end") + return p.Target.DidRenameFiles(ctx, params) +} + +func (p *Server) WillDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (result *lsp.WorkspaceEdit, err error) { + p.Log.Info("client -> server: WillDeleteFiles") + defer p.Log.Info("client -> server: WillDeleteFiles end") + return p.Target.WillDeleteFiles(ctx, params) +} + +func (p *Server) DidDeleteFiles(ctx context.Context, params *lsp.DeleteFilesParams) (err error) { + p.Log.Info("client -> server: DidDeleteFiles") + defer p.Log.Info("client -> server: DidDeleteFiles end") + return p.Target.DidDeleteFiles(ctx, params) +} + +func (p *Server) CodeLensRefresh(ctx context.Context) (err error) { + p.Log.Info("client -> server: CodeLensRefresh") + defer p.Log.Info("client -> server: CodeLensRefresh end") + return p.Target.CodeLensRefresh(ctx) +} + +func (p *Server) PrepareCallHierarchy(ctx context.Context, params *lsp.CallHierarchyPrepareParams) (result []lsp.CallHierarchyItem, err error) { + p.Log.Info("client -> server: PrepareCallHierarchy") + defer p.Log.Info("client -> server: PrepareCallHierarchy end") + return p.Target.PrepareCallHierarchy(ctx, params) +} + +func (p *Server) IncomingCalls(ctx context.Context, params *lsp.CallHierarchyIncomingCallsParams) (result []lsp.CallHierarchyIncomingCall, err error) { + p.Log.Info("client -> server: IncomingCalls") + defer p.Log.Info("client -> server: IncomingCalls end") + return p.Target.IncomingCalls(ctx, params) +} + +func (p *Server) OutgoingCalls(ctx context.Context, params *lsp.CallHierarchyOutgoingCallsParams) (result []lsp.CallHierarchyOutgoingCall, err error) { + p.Log.Info("client -> server: OutgoingCalls") + defer p.Log.Info("client -> server: OutgoingCalls end") + return p.Target.OutgoingCalls(ctx, params) +} + +func (p *Server) SemanticTokensFull(ctx context.Context, params *lsp.SemanticTokensParams) (result *lsp.SemanticTokens, err error) { + p.Log.Info("client -> server: SemanticTokensFull") + defer p.Log.Info("client -> server: SemanticTokensFull end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return nil, nil + } + params.TextDocument.URI = goURI + return p.Target.SemanticTokensFull(ctx, params) +} + +func (p *Server) SemanticTokensFullDelta(ctx context.Context, params *lsp.SemanticTokensDeltaParams) (result any /* SemanticTokens | SemanticTokensDelta */, err error) { + p.Log.Info("client -> server: SemanticTokensFullDelta") + defer p.Log.Info("client -> server: SemanticTokensFullDelta end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return nil, nil + } + params.TextDocument.URI = goURI + return p.Target.SemanticTokensFullDelta(ctx, params) +} + +func (p *Server) SemanticTokensRange(ctx context.Context, params *lsp.SemanticTokensRangeParams) (result *lsp.SemanticTokens, err error) { + p.Log.Info("client -> server: SemanticTokensRange") + defer p.Log.Info("client -> server: SemanticTokensRange end") + isTemplFile, goURI := convertTemplToGoURI(params.TextDocument.URI) + if !isTemplFile { + return nil, nil + } + params.TextDocument.URI = goURI + return p.Target.SemanticTokensRange(ctx, params) +} + +func (p *Server) SemanticTokensRefresh(ctx context.Context) (err error) { + p.Log.Info("client -> server: SemanticTokensRefresh") + defer p.Log.Info("client -> server: SemanticTokensRefresh end") + return p.Target.SemanticTokensRefresh(ctx) +} + +func (p *Server) LinkedEditingRange(ctx context.Context, params *lsp.LinkedEditingRangeParams) (result *lsp.LinkedEditingRanges, err error) { + p.Log.Info("client -> server: LinkedEditingRange") + defer p.Log.Info("client -> server: LinkedEditingRange end") + return p.Target.LinkedEditingRange(ctx, params) +} + +func (p *Server) Moniker(ctx context.Context, params *lsp.MonikerParams) (result []lsp.Moniker, err error) { + p.Log.Info("client -> server: Moniker") + defer p.Log.Info("client -> server: Moniker end") + templURI := params.TextDocument.URI + var ok bool + ok, params.TextDocument.URI, params.TextDocumentPositionParams.Position = p.updatePosition(templURI, params.TextDocumentPositionParams.Position) + if !ok { + return nil, nil + } + return p.Target.Moniker(ctx, params) +} + +func (p *Server) Request(ctx context.Context, method string, params any) (result any, err error) { + p.Log.Info("client -> server: Request") + defer p.Log.Info("client -> server: Request end") + return p.Target.Request(ctx, method, params) +} diff --git a/templ/cmd/templ/lspcmd/proxy/snippets.go b/templ/cmd/templ/lspcmd/proxy/snippets.go new file mode 100644 index 0000000..94580f1 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/snippets.go @@ -0,0 +1,111 @@ +package proxy + +import lsp "github.com/a-h/templ/lsp/protocol" + +var htmlSnippets = []lsp.CompletionItem{ + { + Label: "", + InsertText: `${1}> + ${0} +`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "a", + InsertText: `a href="${1:}">${2:}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "button", + InsertText: `button type="button" ${1:}>${2:}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "div", + InsertText: `div> + ${0} +
`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "p", + InsertText: `p> + ${0} +

`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "head", + InsertText: `head> + ${0} +`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "body", + InsertText: `body> + ${0} +`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "title", + InsertText: `title>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h1", + InsertText: `h1>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h2", + InsertText: `h2>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h3", + InsertText: `h3>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h4", + InsertText: `h4>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h5", + InsertText: `h5>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, + { + Label: "h6", + InsertText: `h6>${0}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, +} + +var snippet = []lsp.CompletionItem{ + { + Label: "templ", + InsertText: `templ ${2:TemplateName}() { + ${0} +}`, + Kind: lsp.CompletionItemKind(lsp.CompletionItemKindSnippet), + InsertTextFormat: lsp.InsertTextFormatSnippet, + }, +} diff --git a/templ/cmd/templ/lspcmd/proxy/sourcemapcache.go b/templ/cmd/templ/lspcmd/proxy/sourcemapcache.go new file mode 100644 index 0000000..ccf9024 --- /dev/null +++ b/templ/cmd/templ/lspcmd/proxy/sourcemapcache.go @@ -0,0 +1,52 @@ +package proxy + +import ( + "sync" + + "github.com/a-h/templ/parser/v2" +) + +// NewSourceMapCache creates a cache of .templ file URIs to the source map. +func NewSourceMapCache() *SourceMapCache { + return &SourceMapCache{ + m: new(sync.Mutex), + uriToSourceMap: make(map[string]*parser.SourceMap), + } +} + +// SourceMapCache is a cache of .templ file URIs to the source map. +type SourceMapCache struct { + m *sync.Mutex + uriToSourceMap map[string]*parser.SourceMap +} + +func (fc *SourceMapCache) Set(uri string, m *parser.SourceMap) { + fc.m.Lock() + defer fc.m.Unlock() + fc.uriToSourceMap[uri] = m +} + +func (fc *SourceMapCache) Get(uri string) (m *parser.SourceMap, ok bool) { + fc.m.Lock() + defer fc.m.Unlock() + m, ok = fc.uriToSourceMap[uri] + return +} + +func (fc *SourceMapCache) Delete(uri string) { + fc.m.Lock() + defer fc.m.Unlock() + delete(fc.uriToSourceMap, uri) +} + +func (fc *SourceMapCache) URIs() (uris []string) { + fc.m.Lock() + defer fc.m.Unlock() + uris = make([]string, len(fc.uriToSourceMap)) + var i int + for k := range fc.uriToSourceMap { + uris[i] = k + i++ + } + return uris +} diff --git a/templ/cmd/templ/lspcmd/stdrwc.go b/templ/cmd/templ/lspcmd/stdrwc.go new file mode 100644 index 0000000..28d9f44 --- /dev/null +++ b/templ/cmd/templ/lspcmd/stdrwc.go @@ -0,0 +1,50 @@ +package lspcmd + +import ( + "errors" + "io" + "log/slog" +) + +// stdrwc (standard read/write closer) reads from stdin, and writes to stdout. +func newStdRwc(log *slog.Logger, name string, w io.Writer, r io.Reader) stdrwc { + return stdrwc{ + log: log, + name: name, + w: w, + r: r, + } +} + +type stdrwc struct { + log *slog.Logger + name string + w io.Writer + r io.Reader +} + +func (s stdrwc) Read(p []byte) (int, error) { + return s.r.Read(p) +} + +func (s stdrwc) Write(p []byte) (int, error) { + return s.w.Write(p) +} + +func (s stdrwc) Close() error { + s.log.Info("rwc: closing", slog.String("name", s.name)) + var errs []error + if closer, isCloser := s.r.(io.Closer); isCloser { + if err := closer.Close(); err != nil { + s.log.Error("rwc: error closing reader", slog.String("name", s.name), slog.Any("error", err)) + errs = append(errs, err) + } + } + if closer, isCloser := s.w.(io.Closer); isCloser { + if err := closer.Close(); err != nil { + s.log.Error("rwc: error closing writer", slog.String("name", s.name), slog.Any("error", err)) + errs = append(errs, err) + } + } + return errors.Join(errs...) +} diff --git a/templ/cmd/templ/main.go b/templ/cmd/templ/main.go new file mode 100644 index 0000000..6e149cb --- /dev/null +++ b/templ/cmd/templ/main.go @@ -0,0 +1,394 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "log/slog" + "os" + "os/signal" + "runtime" + + "github.com/a-h/templ" + "github.com/a-h/templ/cmd/templ/fmtcmd" + "github.com/a-h/templ/cmd/templ/generatecmd" + "github.com/a-h/templ/cmd/templ/infocmd" + "github.com/a-h/templ/cmd/templ/lspcmd" + "github.com/a-h/templ/cmd/templ/sloghandler" + "github.com/fatih/color" +) + +func main() { + code := run(os.Stdin, os.Stdout, os.Stderr, os.Args) + if code != 0 { + os.Exit(code) + } +} + +const usageText = `usage: templ [...] + +templ - build HTML UIs with Go + +See docs at https://templ.guide + +commands: + generate Generates Go code from templ files + fmt Formats templ files + lsp Starts a language server for templ files + info Displays information about the templ environment + version Prints the version +` + +func run(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { + if len(args) < 2 { + fmt.Fprint(stderr, usageText) + return 64 // EX_USAGE + } + switch args[1] { + case "info": + return infoCmd(stdout, stderr, args[2:]) + case "generate": + return generateCmd(stdout, stderr, args[2:]) + case "fmt": + return fmtCmd(stdin, stdout, stderr, args[2:]) + case "lsp": + return lspCmd(stdin, stdout, stderr, args[2:]) + case "version", "--version": + fmt.Fprintln(stdout, templ.Version()) + return 0 + case "help", "-help", "--help", "-h": + fmt.Fprint(stdout, usageText) + return 0 + } + fmt.Fprint(stderr, usageText) + return 64 // EX_USAGE +} + +func newLogger(logLevel string, verbose bool, stderr io.Writer) *slog.Logger { + if verbose { + logLevel = "debug" + } + level := slog.LevelInfo.Level() + switch logLevel { + case "debug": + level = slog.LevelDebug.Level() + case "warn": + level = slog.LevelWarn.Level() + case "error": + level = slog.LevelError.Level() + } + return slog.New(sloghandler.NewHandler(stderr, &slog.HandlerOptions{ + AddSource: logLevel == "debug", + Level: level, + })) +} + +const infoUsageText = `usage: templ info [...] + +Displays information about the templ environment. + +Args: + -json + Output information in JSON format to stdout. (default false) + -v + Set log verbosity level to "debug". (default "info") + -log-level + Set log verbosity level. (default "info", options: "debug", "info", "warn", "error") + -help + Print help and exit. +` + +func infoCmd(stdout, stderr io.Writer, args []string) (code int) { + cmd := flag.NewFlagSet("diagnose", flag.ExitOnError) + jsonFlag := cmd.Bool("json", false, "") + verboseFlag := cmd.Bool("v", false, "") + logLevelFlag := cmd.String("log-level", "info", "") + helpFlag := cmd.Bool("help", false, "") + err := cmd.Parse(args) + if err != nil { + fmt.Fprint(stderr, infoUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, infoUsageText) + return + } + + log := newLogger(*logLevelFlag, *verboseFlag, stderr) + + ctx, cancel := context.WithCancel(context.Background()) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + go func() { + <-signalChan + fmt.Fprintln(stderr, "Stopping...") + cancel() + }() + + err = infocmd.Run(ctx, log, stdout, infocmd.Arguments{ + JSON: *jsonFlag, + }) + if err != nil { + color.New(color.FgRed).Fprint(stderr, "(✗) ") + fmt.Fprintln(stderr, "Command failed: "+err.Error()) + return 1 + } + return 0 +} + +const generateUsageText = `usage: templ generate [...] + +Generates Go code from templ files. + +Args: + -path + Generates code for all files in path. (default .) + -f + Optionally generates code for a single file, e.g. -f header.templ + -stdout + Prints to stdout instead of writing generated files to the filesystem. + Only applicable when -f is used. + -source-map-visualisations + Set to true to generate HTML files to visualise the templ code and its corresponding Go code. + -include-version + Set to false to skip inclusion of the templ version in the generated code. (default true) + -include-timestamp + Set to true to include the current time in the generated code. + -watch + Set to true to watch the path for changes and regenerate code. + -watch-pattern + Set the regexp pattern of files that will be watched for changes. (default: '(.+\.go$)|(.+\.templ$)|(.+_templ\.txt$)') + -cmd + Set the command to run after generating code. + -proxy + Set the URL to proxy after generating code and executing the command. + -proxyport + The port the proxy will listen on. (default 7331) + -proxybind + The address the proxy will listen on. (default 127.0.0.1) + -notify-proxy + If present, the command will issue a reload event to the proxy 127.0.0.1:7331, or use proxyport and proxybind to specify a different address. + -w + Number of workers to use when generating code. (default runtime.NumCPUs) + -lazy + Only generate .go files if the source .templ file is newer. + -pprof + Port to run the pprof server on. + -keep-orphaned-files + Keeps orphaned generated templ files. (default false) + -v + Set log verbosity level to "debug". (default "info") + -log-level + Set log verbosity level. (default "info", options: "debug", "info", "warn", "error") + -help + Print help and exit. + +Examples: + + Generate code for all files in the current directory and subdirectories: + + templ generate + + Generate code for a single file: + + templ generate -f header.templ + + Watch the current directory and subdirectories for changes and regenerate code: + + templ generate -watch +` + +func generateCmd(stdout, stderr io.Writer, args []string) (code int) { + cmd := flag.NewFlagSet("generate", flag.ExitOnError) + fileNameFlag := cmd.String("f", "", "") + pathFlag := cmd.String("path", ".", "") + toStdoutFlag := cmd.Bool("stdout", false, "") + sourceMapVisualisationsFlag := cmd.Bool("source-map-visualisations", false, "") + includeVersionFlag := cmd.Bool("include-version", true, "") + includeTimestampFlag := cmd.Bool("include-timestamp", false, "") + watchFlag := cmd.Bool("watch", false, "") + watchPatternFlag := cmd.String("watch-pattern", "(.+\\.go$)|(.+\\.templ$)|(.+_templ\\.txt$)", "") + openBrowserFlag := cmd.Bool("open-browser", true, "") + cmdFlag := cmd.String("cmd", "", "") + proxyFlag := cmd.String("proxy", "", "") + proxyPortFlag := cmd.Int("proxyport", 7331, "") + proxyBindFlag := cmd.String("proxybind", "127.0.0.1", "") + notifyProxyFlag := cmd.Bool("notify-proxy", false, "") + workerCountFlag := cmd.Int("w", runtime.NumCPU(), "") + pprofPortFlag := cmd.Int("pprof", 0, "") + keepOrphanedFilesFlag := cmd.Bool("keep-orphaned-files", false, "") + verboseFlag := cmd.Bool("v", false, "") + logLevelFlag := cmd.String("log-level", "info", "") + lazyFlag := cmd.Bool("lazy", false, "") + helpFlag := cmd.Bool("help", false, "") + err := cmd.Parse(args) + if err != nil { + fmt.Fprint(stderr, generateUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, generateUsageText) + return + } + + log := newLogger(*logLevelFlag, *verboseFlag, stderr) + + ctx, cancel := context.WithCancel(context.Background()) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + go func() { + <-signalChan + fmt.Fprintln(stderr, "Stopping...") + cancel() + }() + + var fw generatecmd.FileWriterFunc + if *toStdoutFlag { + fw = generatecmd.WriterFileWriter(stdout) + } + + err = generatecmd.Run(ctx, log, generatecmd.Arguments{ + FileName: *fileNameFlag, + Path: *pathFlag, + FileWriter: fw, + Watch: *watchFlag, + WatchPattern: *watchPatternFlag, + OpenBrowser: *openBrowserFlag, + Command: *cmdFlag, + Proxy: *proxyFlag, + ProxyPort: *proxyPortFlag, + ProxyBind: *proxyBindFlag, + NotifyProxy: *notifyProxyFlag, + WorkerCount: *workerCountFlag, + GenerateSourceMapVisualisations: *sourceMapVisualisationsFlag, + IncludeVersion: *includeVersionFlag, + IncludeTimestamp: *includeTimestampFlag, + PPROFPort: *pprofPortFlag, + KeepOrphanedFiles: *keepOrphanedFilesFlag, + Lazy: *lazyFlag, + }) + if err != nil { + color.New(color.FgRed).Fprint(stderr, "(✗) ") + fmt.Fprintln(stderr, "Command failed: "+err.Error()) + return 1 + } + return 0 +} + +const fmtUsageText = `usage: templ fmt [ ...] + +Format all files in directory: + + templ fmt . + +Format stdin to stdout: + + templ fmt < header.templ + +Format file or directory to stdout: + + templ fmt -stdout FILE + +Args: + -stdout + Prints to stdout instead of in-place format + -stdin-filepath + Provides the formatter with filepath context when using -stdout. + Required for organising imports. + -v + Set log verbosity level to "debug". (default "info") + -log-level + Set log verbosity level. (default "info", options: "debug", "info", "warn", "error") + -w + Number of workers to use when formatting code. (default runtime.NumCPUs). + -fail + Fails with exit code 1 if files are changed. (e.g. in CI) + -help + Print help and exit. +` + +func fmtCmd(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { + cmd := flag.NewFlagSet("fmt", flag.ExitOnError) + helpFlag := cmd.Bool("help", false, "") + workerCountFlag := cmd.Int("w", runtime.NumCPU(), "") + verboseFlag := cmd.Bool("v", false, "") + logLevelFlag := cmd.String("log-level", "info", "") + failIfChanged := cmd.Bool("fail", false, "") + stdoutFlag := cmd.Bool("stdout", false, "") + stdinFilepath := cmd.String("stdin-filepath", "", "") + err := cmd.Parse(args) + if err != nil { + fmt.Fprint(stderr, fmtUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, fmtUsageText) + return + } + + log := newLogger(*logLevelFlag, *verboseFlag, stderr) + + err = fmtcmd.Run(log, stdin, stdout, fmtcmd.Arguments{ + ToStdout: *stdoutFlag, + Files: cmd.Args(), + WorkerCount: *workerCountFlag, + StdinFilepath: *stdinFilepath, + FailIfChanged: *failIfChanged, + }) + if err != nil { + return 1 + } + return 0 +} + +const lspUsageText = `usage: templ lsp [ ...] + +Starts a language server for templ. + +Args: + -log string + The file to log templ LSP output to, or leave empty to disable logging. + -goplsLog string + The file to log gopls output, or leave empty to disable logging. + -goplsRPCTrace + Set gopls to log input and output messages. + -help + Print help and exit. + -pprof + Enable pprof web server (default address is localhost:9999) + -http string + Enable http debug server by setting a listen address (e.g. localhost:7474) +` + +func lspCmd(stdin io.Reader, stdout, stderr io.Writer, args []string) (code int) { + cmd := flag.NewFlagSet("lsp", flag.ExitOnError) + logFlag := cmd.String("log", "", "") + goplsLog := cmd.String("goplsLog", "", "") + goplsRPCTrace := cmd.Bool("goplsRPCTrace", false, "") + helpFlag := cmd.Bool("help", false, "") + pprofFlag := cmd.Bool("pprof", false, "") + httpDebugFlag := cmd.String("http", "", "") + err := cmd.Parse(args) + if err != nil { + fmt.Fprint(stderr, lspUsageText) + return 64 // EX_USAGE + } + if *helpFlag { + fmt.Fprint(stdout, lspUsageText) + return + } + + err = lspcmd.Run(stdin, stdout, stderr, lspcmd.Arguments{ + Log: *logFlag, + GoplsLog: *goplsLog, + GoplsRPCTrace: *goplsRPCTrace, + PPROF: *pprofFlag, + HTTPDebug: *httpDebugFlag, + }) + if err != nil { + fmt.Fprintln(stderr, err.Error()) + return 1 + } + return 0 +} diff --git a/templ/cmd/templ/main_test.go b/templ/cmd/templ/main_test.go new file mode 100644 index 0000000..5f05982 --- /dev/null +++ b/templ/cmd/templ/main_test.go @@ -0,0 +1,102 @@ +package main + +import ( + "bytes" + "strings" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestMain(t *testing.T) { + tests := []struct { + name string + args []string + expectedStdout string + expectedStderr string + expectedCode int + }{ + { + name: "no args prints usage", + args: []string{}, + expectedStderr: usageText, + expectedCode: 64, // EX_USAGE + }, + { + name: `"templ help" prints help`, + args: []string{"templ", "help"}, + expectedStdout: usageText, + expectedCode: 0, + }, + { + name: `"templ --help" prints help`, + args: []string{"templ", "--help"}, + expectedStdout: usageText, + expectedCode: 0, + }, + { + name: `"templ version" prints version`, + args: []string{"templ", "version"}, + expectedStdout: templ.Version() + "\n", + expectedCode: 0, + }, + { + name: `"templ --version" prints version`, + args: []string{"templ", "--version"}, + expectedStdout: templ.Version() + "\n", + expectedCode: 0, + }, + { + name: `"templ fmt --help" prints usage`, + args: []string{"templ", "fmt", "--help"}, + expectedStdout: fmtUsageText, + expectedCode: 0, + }, + { + name: `"templ generate --help" prints usage`, + args: []string{"templ", "generate", "--help"}, + expectedStdout: generateUsageText, + expectedCode: 0, + }, + { + name: `"templ lsp --help" prints usage`, + args: []string{"templ", "lsp", "--help"}, + expectedStdout: lspUsageText, + expectedCode: 0, + }, + { + name: `"templ info --help" prints usage`, + args: []string{"templ", "info", "--help"}, + expectedStdout: infoUsageText, + expectedCode: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + stdin := strings.NewReader("") + stdout := bytes.NewBuffer(nil) + stderr := bytes.NewBuffer(nil) + actualCode := run(stdin, stdout, stderr, test.args) + + if actualCode != test.expectedCode { + t.Errorf("expected code %v, got %v", test.expectedCode, actualCode) + } + if diff := cmp.Diff(test.expectedStdout, stdout.String()); diff != "" { + t.Error(diff) + t.Error("expected stdout:") + t.Error(test.expectedStdout) + t.Error("actual stdout:") + t.Error(stdout.String()) + } + if diff := cmp.Diff(test.expectedStderr, stderr.String()); diff != "" { + t.Error(diff) + t.Error("expected stderr:") + t.Error(test.expectedStderr) + t.Error("actual stderr:") + t.Error(stderr.String()) + } + }) + } +} diff --git a/templ/cmd/templ/processor/processor.go b/templ/cmd/templ/processor/processor.go new file mode 100644 index 0000000..7f0466c --- /dev/null +++ b/templ/cmd/templ/processor/processor.go @@ -0,0 +1,80 @@ +package processor + +import ( + "io/fs" + "path" + "path/filepath" + "strings" + "sync" + "time" +) + +type Result struct { + FileName string + Duration time.Duration + Error error + ChangesMade bool +} + +func Process(dir string, f func(fileName string) (error, bool), workerCount int, results chan<- Result) { + templates := make(chan string) + go func() { + defer close(templates) + if err := FindTemplates(dir, templates); err != nil { + results <- Result{Error: err} + } + }() + ProcessChannel(templates, dir, f, workerCount, results) +} + +func shouldSkipDir(dir string) bool { + if dir == "." { + return false + } + if dir == "vendor" || dir == "node_modules" { + return true + } + _, name := path.Split(dir) + // These directories are ignored by the Go tool. + if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") { + return true + } + return false +} + +func FindTemplates(srcPath string, output chan<- string) (err error) { + return filepath.WalkDir(srcPath, func(currentPath string, info fs.DirEntry, err error) error { + if err != nil { + return err + } + if info.IsDir() && shouldSkipDir(currentPath) { + return filepath.SkipDir + } + if !info.IsDir() && strings.HasSuffix(currentPath, ".templ") { + output <- currentPath + } + return nil + }) +} + +func ProcessChannel(templates <-chan string, dir string, f func(fileName string) (error, bool), workerCount int, results chan<- Result) { + defer close(results) + var wg sync.WaitGroup + wg.Add(workerCount) + for i := 0; i < workerCount; i++ { + go func() { + defer wg.Done() + for sourceFileName := range templates { + start := time.Now() + outErr, outChanged := f(sourceFileName) + results <- Result{ + FileName: sourceFileName, + Error: outErr, + Duration: time.Since(start), + ChangesMade: outChanged, + } + } + }() + } + wg.Wait() +} diff --git a/templ/cmd/templ/processor/processor_test.go b/templ/cmd/templ/processor/processor_test.go new file mode 100644 index 0000000..438ac2d --- /dev/null +++ b/templ/cmd/templ/processor/processor_test.go @@ -0,0 +1,19 @@ +package processor + +import ( + "os" + "testing" +) + +func TestFindTemplates(t *testing.T) { + t.Run("returns an error if the directory does not exist", func(t *testing.T) { + output := make(chan string) + err := FindTemplates("nonexistent", output) + if err == nil { + t.Fatal("expected error, but got nil") + } + if !os.IsNotExist(err) { + t.Fatalf("expected os.IsNotExist(err) to be true, but got: %v", err) + } + }) +} diff --git a/templ/cmd/templ/sloghandler/handler.go b/templ/cmd/templ/sloghandler/handler.go new file mode 100644 index 0000000..289405d --- /dev/null +++ b/templ/cmd/templ/sloghandler/handler.go @@ -0,0 +1,101 @@ +package sloghandler + +import ( + "context" + "io" + "log/slog" + "strings" + "sync" + + "github.com/fatih/color" +) + +var _ slog.Handler = &Handler{} + +type Handler struct { + h slog.Handler + m *sync.Mutex + w io.Writer +} + +var levelToIcon = map[slog.Level]string{ + slog.LevelDebug: "(✓)", + slog.LevelInfo: "(✓)", + slog.LevelWarn: "(!)", + slog.LevelError: "(✗)", +} +var levelToColor = map[slog.Level]*color.Color{ + slog.LevelDebug: color.New(color.FgCyan), + slog.LevelInfo: color.New(color.FgGreen), + slog.LevelWarn: color.New(color.FgYellow), + slog.LevelError: color.New(color.FgRed), +} + +func NewHandler(w io.Writer, opts *slog.HandlerOptions) *Handler { + if opts == nil { + opts = &slog.HandlerOptions{} + } + return &Handler{ + w: w, + h: slog.NewTextHandler(w, &slog.HandlerOptions{ + Level: opts.Level, + AddSource: opts.AddSource, + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + if opts.ReplaceAttr != nil { + a = opts.ReplaceAttr(groups, a) + } + if a.Key == slog.LevelKey { + level, ok := levelToIcon[a.Value.Any().(slog.Level)] + if !ok { + level = a.Value.Any().(slog.Level).String() + } + a.Value = slog.StringValue(level) + return a + } + if a.Key == slog.TimeKey { + return slog.Attr{} + } + return a + }, + }), + m: &sync.Mutex{}, + } +} + +func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool { + return h.h.Enabled(ctx, level) +} + +func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &Handler{h: h.h.WithAttrs(attrs), w: h.w, m: h.m} +} + +func (h *Handler) WithGroup(name string) slog.Handler { + return &Handler{h: h.h.WithGroup(name), w: h.w, m: h.m} +} + +var keyValueColor = color.New(color.Faint & color.FgBlack) + +func (h *Handler) Handle(ctx context.Context, r slog.Record) (err error) { + var sb strings.Builder + + sb.WriteString(levelToColor[r.Level].Sprint(levelToIcon[r.Level])) + sb.WriteString(" ") + sb.WriteString(r.Message) + + if r.NumAttrs() != 0 { + sb.WriteString(" [") + r.Attrs(func(a slog.Attr) bool { + sb.WriteString(keyValueColor.Sprintf(" %s=%s", a.Key, a.Value.String())) + return true + }) + sb.WriteString(" ]") + } + + sb.WriteString("\n") + + h.m.Lock() + defer h.m.Unlock() + _, err = io.WriteString(h.w, sb.String()) + return err +} diff --git a/templ/cmd/templ/testproject/testdata/css-classes/classes.go b/templ/cmd/templ/testproject/testdata/css-classes/classes.go new file mode 100644 index 0000000..3cedc02 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/css-classes/classes.go @@ -0,0 +1,3 @@ +package cssclasses + +const Header = "header" diff --git a/templ/cmd/templ/testproject/testdata/go.mod.embed b/templ/cmd/templ/testproject/testdata/go.mod.embed new file mode 100644 index 0000000..bff4974 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/go.mod.embed @@ -0,0 +1,7 @@ +module templ/testproject + +go 1.23 + +require github.com/a-h/templ v0.2.513 // indirect + +replace github.com/a-h/templ => {moduleRoot} diff --git a/templ/cmd/templ/testproject/testdata/go.sum b/templ/cmd/templ/testproject/testdata/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/cmd/templ/testproject/testdata/main.go b/templ/cmd/templ/testproject/testdata/main.go new file mode 100644 index 0000000..d631386 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + "os" + + "github.com/a-h/templ" +) + +var flagPort = flag.Int("port", 0, "Set the HTTP listen port") + +func main() { + flag.Parse() + + if *flagPort == 0 { + fmt.Println("missing port flag") + os.Exit(1) + } + + var count int + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + count++ + c := Page(count) + templ.Handler(c).ServeHTTP(w, r) + }) + err := http.ListenAndServe(fmt.Sprintf("localhost:%d", *flagPort), nil) + if err != nil { + fmt.Printf("Error listening: %v\n", err) + os.Exit(1) + } +} diff --git a/templ/cmd/templ/testproject/testdata/remotechild.templ b/templ/cmd/templ/testproject/testdata/remotechild.templ new file mode 100644 index 0000000..17366ea --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/remotechild.templ @@ -0,0 +1,5 @@ +package main + +templ Remote() { +

This is remote content

+} diff --git a/templ/cmd/templ/testproject/testdata/remotechild_templ.go b/templ/cmd/templ/testproject/testdata/remotechild_templ.go new file mode 100644 index 0000000..6aa8814 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/remotechild_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Remote() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

This is remote content

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/testproject/testdata/remoteparent.templ b/templ/cmd/templ/testproject/testdata/remoteparent.templ new file mode 100644 index 0000000..bf66800 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/remoteparent.templ @@ -0,0 +1,9 @@ +package main + +templ RemoteInclusionTest() { + @Remote +} + +templ Remote2() { + @Remote +} diff --git a/templ/cmd/templ/testproject/testdata/remoteparent_templ.go b/templ/cmd/templ/testproject/testdata/remoteparent_templ.go new file mode 100644 index 0000000..4299c29 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/remoteparent_templ.go @@ -0,0 +1,69 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func RemoteInclusionTest() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Remote.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Remote2() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Remote.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/testproject/testdata/templates.templ b/templ/cmd/templ/testproject/testdata/templates.templ new file mode 100644 index 0000000..05e2573 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/templates.templ @@ -0,0 +1,25 @@ +package main + +import "fmt" + +templ Page(count int) { + + + + templ test page + + +

Count

+
{ fmt.Sprintf("%d", count) }
+
Original
+ + +} + +var nihao = "你好" + +type Struct struct { + Count int +} + +var s = Struct{} diff --git a/templ/cmd/templ/testproject/testdata/templates_templ.go b/templ/cmd/templ/testproject/testdata/templates_templ.go new file mode 100644 index 0000000..d148e38 --- /dev/null +++ b/templ/cmd/templ/testproject/testdata/templates_templ.go @@ -0,0 +1,63 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func Page(count int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "templ test page

Count

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", count)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/testproject/testdata/templates.templ`, Line: 13, Col: 54} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Original
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var nihao = "你好" + +type Struct struct { + Count int +} + +var s = Struct{} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/testproject/testproject.go b/templ/cmd/templ/testproject/testproject.go new file mode 100644 index 0000000..f7d9f17 --- /dev/null +++ b/templ/cmd/templ/testproject/testproject.go @@ -0,0 +1,70 @@ +package testproject + +import ( + "bytes" + "embed" + "fmt" + "os" + "path/filepath" + "strings" +) + +//go:embed testdata/* +var testdata embed.FS + +func Create(moduleRoot string) (dir string, err error) { + dir, err = os.MkdirTemp("", "templ_test_*") + if err != nil { + return dir, fmt.Errorf("failed to make test dir: %w", err) + } + files, err := testdata.ReadDir("testdata") + if err != nil { + return dir, fmt.Errorf("failed to read embedded dir: %w", err) + } + for _, file := range files { + if file.IsDir() { + if err = os.MkdirAll(filepath.Join(dir, file.Name()), 0777); err != nil { + return dir, fmt.Errorf("failed to create dir: %w", err) + } + continue + } + src := filepath.Join("testdata", file.Name()) + data, err := testdata.ReadFile(src) + if err != nil { + return dir, fmt.Errorf("failed to read file: %w", err) + } + + target := filepath.Join(dir, file.Name()) + if file.Name() == "go.mod.embed" { + data = bytes.ReplaceAll(data, []byte("{moduleRoot}"), []byte(moduleRoot)) + target = filepath.Join(dir, "go.mod") + } + err = os.WriteFile(target, data, 0660) + if err != nil { + return dir, fmt.Errorf("failed to copy file: %w", err) + } + } + files, err = testdata.ReadDir("testdata/css-classes") + if err != nil { + return dir, fmt.Errorf("failed to read embedded dir: %w", err) + } + for _, file := range files { + src := filepath.Join("testdata", "css-classes", file.Name()) + data, err := testdata.ReadFile(src) + if err != nil { + return dir, fmt.Errorf("failed to read file: %w", err) + } + target := filepath.Join(dir, "css-classes", file.Name()) + err = os.WriteFile(target, data, 0660) + if err != nil { + return dir, fmt.Errorf("failed to copy file: %w", err) + } + } + return dir, nil +} + +func MustReplaceLine(file string, line int, replacement string) string { + lines := strings.Split(file, "\n") + lines[line-1] = replacement + return strings.Join(lines, "\n") +} diff --git a/templ/cmd/templ/visualize/sourcemapvisualisation.templ b/templ/cmd/templ/visualize/sourcemapvisualisation.templ new file mode 100644 index 0000000..6d4d5d1 --- /dev/null +++ b/templ/cmd/templ/visualize/sourcemapvisualisation.templ @@ -0,0 +1,64 @@ +package visualize + +css row() { + display: flex; +} + +css column() { + flex: 50%; + overflow-y: scroll; + max-height: 100vh; +} + +css code() { + font-family: monospace; +} + +templ combine(templFileName string, left, right templ.Component) { + + + { templFileName }- Source Map Visualisation + + + +

{ templFileName }

+
+
+ @left +
+
+ @right +
+
+ + +} + +script highlight(sourceId, targetId string) { + let items = document.getElementsByClassName(sourceId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.add("highlighted"); + } + items = document.getElementsByClassName(targetId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.add("highlighted"); + } +} + +script removeHighlight(sourceId, targetId string) { + let items = document.getElementsByClassName(sourceId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.remove("highlighted"); + } + items = document.getElementsByClassName(targetId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.remove("highlighted"); + } +} + +templ mappedCharacter(s string, sourceID, targetID string) { + { s } +} diff --git a/templ/cmd/templ/visualize/sourcemapvisualisation_templ.go b/templ/cmd/templ/visualize/sourcemapvisualisation_templ.go new file mode 100644 index 0000000..28fd57a --- /dev/null +++ b/templ/cmd/templ/visualize/sourcemapvisualisation_templ.go @@ -0,0 +1,296 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package visualize + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func row() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`display:flex;`) + templ_7745c5c3_CSSID := templ.CSSID(`row`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func column() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`flex:50%;`) + templ_7745c5c3_CSSBuilder.WriteString(`overflow-y:scroll;`) + templ_7745c5c3_CSSBuilder.WriteString(`max-height:100vh;`) + templ_7745c5c3_CSSID := templ.CSSID(`column`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func code() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`font-family:monospace;`) + templ_7745c5c3_CSSID := templ.CSSID(`code`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func combine(templFileName string, left, right templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(templFileName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/visualize/sourcemapvisualisation.templ`, Line: 20, Col: 25} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "- Source Map Visualisation

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templFileName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/visualize/sourcemapvisualisation.templ`, Line: 27, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 = []any{templ.Classes(row())} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 = []any{templ.Classes(column(), code())} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = left.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 = []any{templ.Classes(column(), code())} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = right.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func highlight(sourceId, targetId string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_highlight_ae80`, + Function: `function __templ_highlight_ae80(sourceId, targetId){let items = document.getElementsByClassName(sourceId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.add("highlighted"); + } + items = document.getElementsByClassName(targetId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.add("highlighted"); + } +}`, + Call: templ.SafeScript(`__templ_highlight_ae80`, sourceId, targetId), + CallInline: templ.SafeScriptInline(`__templ_highlight_ae80`, sourceId, targetId), + } +} + +func removeHighlight(sourceId, targetId string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_removeHighlight_58f2`, + Function: `function __templ_removeHighlight_58f2(sourceId, targetId){let items = document.getElementsByClassName(sourceId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.remove("highlighted"); + } + items = document.getElementsByClassName(targetId); + for(let i = 0; i < items.length; i ++) { + items[i].classList.remove("highlighted"); + } +}`, + Call: templ.SafeScript(`__templ_removeHighlight_58f2`, sourceId, targetId), + CallInline: templ.SafeScriptInline(`__templ_removeHighlight_58f2`, sourceId, targetId), + } +} + +func mappedCharacter(s string, sourceID, targetID string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var11 = []any{templ.Classes(templ.Class("mapped"), templ.Class(sourceID), templ.Class(targetID))} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, highlight(sourceID, targetID), removeHighlight(sourceID, targetID)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(s) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/cmd/templ/visualize/sourcemapvisualisation.templ`, Line: 63, Col: 200} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/cmd/templ/visualize/types.go b/templ/cmd/templ/visualize/types.go new file mode 100644 index 0000000..4a8c49a --- /dev/null +++ b/templ/cmd/templ/visualize/types.go @@ -0,0 +1,87 @@ +package visualize + +import ( + "context" + "fmt" + "html" + "io" + "strconv" + "strings" + + "github.com/a-h/templ" + "github.com/a-h/templ/parser/v2" +) + +func HTML(templFileName string, templContents, goContents string, sourceMap *parser.SourceMap) templ.Component { + tl := templLines{contents: string(templContents), sourceMap: sourceMap} + gl := goLines{contents: string(goContents), sourceMap: sourceMap} + return combine(templFileName, tl, gl) +} + +type templLines struct { + contents string + sourceMap *parser.SourceMap +} + +func (tl templLines) Render(ctx context.Context, w io.Writer) (err error) { + templLines := strings.Split(tl.contents, "\n") + for lineIndex, line := range templLines { + if _, err = w.Write([]byte("" + strconv.Itoa(lineIndex) + " \n")); err != nil { + return + } + for colIndex, c := range line { + if tgt, ok := tl.sourceMap.TargetPositionFromSource(uint32(lineIndex), uint32(colIndex)); ok { + sourceID := fmt.Sprintf("src_%d_%d", lineIndex, colIndex) + targetID := fmt.Sprintf("tgt_%d_%d", tgt.Line, tgt.Col) + if err := mappedCharacter(string(c), sourceID, targetID).Render(ctx, w); err != nil { + return err + } + } else { + s := html.EscapeString(string(c)) + s = strings.ReplaceAll(s, "\t", " ") + s = strings.ReplaceAll(s, " ", " ") + if _, err := w.Write([]byte(s)); err != nil { + return err + } + } + } + if _, err = w.Write([]byte("\n
\n")); err != nil { + return + } + } + return nil +} + +type goLines struct { + contents string + sourceMap *parser.SourceMap +} + +func (gl goLines) Render(ctx context.Context, w io.Writer) (err error) { + templLines := strings.Split(gl.contents, "\n") + for lineIndex, line := range templLines { + if _, err = w.Write([]byte("" + strconv.Itoa(lineIndex) + " \n")); err != nil { + return + } + for colIndex, c := range line { + if src, ok := gl.sourceMap.SourcePositionFromTarget(uint32(lineIndex), uint32(colIndex)); ok { + sourceID := fmt.Sprintf("src_%d_%d", src.Line, src.Col) + targetID := fmt.Sprintf("tgt_%d_%d", lineIndex, colIndex) + if err := mappedCharacter(string(c), sourceID, targetID).Render(ctx, w); err != nil { + return err + } + } else { + s := html.EscapeString(string(c)) + s = strings.ReplaceAll(s, "\t", " ") + s = strings.ReplaceAll(s, " ", " ") + if _, err := w.Write([]byte(s)); err != nil { + return err + } + } + } + if _, err = w.Write([]byte("\n
\n")); err != nil { + return + } + } + return nil +} diff --git a/templ/cosign.pub b/templ/cosign.pub new file mode 100644 index 0000000..9d7967b --- /dev/null +++ b/templ/cosign.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqHp75uAj8XqKrLO2YvY0M2EddckH +evQnNAj+0GmBptqdf3NJcUCjL6w4z2Ikh/Zb8lh6b13akAwO/dJQaMLoMA== +-----END PUBLIC KEY----- diff --git a/templ/docs/.gitignore b/templ/docs/.gitignore new file mode 100644 index 0000000..c1dd494 --- /dev/null +++ b/templ/docs/.gitignore @@ -0,0 +1,22 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +/static/llms.md diff --git a/templ/docs/README.md b/templ/docs/README.md new file mode 100644 index 0000000..aaba2fa --- /dev/null +++ b/templ/docs/README.md @@ -0,0 +1,41 @@ +# Website + +This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +``` +$ USE_SSH=true yarn deploy +``` + +Not using SSH: + +``` +$ GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/templ/docs/babel.config.js b/templ/docs/babel.config.js new file mode 100644 index 0000000..e00595d --- /dev/null +++ b/templ/docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/templ/docs/docs/02-quick-start/01-installation.md b/templ/docs/docs/02-quick-start/01-installation.md new file mode 100644 index 0000000..7a2d20e --- /dev/null +++ b/templ/docs/docs/02-quick-start/01-installation.md @@ -0,0 +1,138 @@ +# Installation + +## go install + +With Go 1.23 or greater installed, run: + +```bash +go install github.com/a-h/templ/cmd/templ@latest +``` + +## GitHub binaries + +Download the latest release from https://github.com/a-h/templ/releases/latest + +## Nix + +templ provides a Nix flake with an exported package containing the binary at https://github.com/a-h/templ/blob/main/flake.nix + +```bash +nix run github:a-h/templ +``` + +templ also provides a development shell which includes all of the tools required to build templ, e.g. go, gopls etc. but not templ itself. + +```bash +nix develop github:a-h/templ +``` + +To install in your Nix Flake: + +This flake exposes an overlay, so you can add it to your own Flake and/or NixOS system. + +```nix +{ + inputs = { + ... + templ.url = "github:a-h/templ"; + ... + }; + outputs = inputs@{ + ... + }: + + # For NixOS configuration: + { + # Add the overlay, + nixpkgs.overlays = [ + inputs.templ.overlays.default + ]; + # and install the package + environment.systemPackages = with pkgs; [ + templ + ]; + }; + + # For a flake project: + let + forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { + inherit system; + pkgs = import nixpkgs { inherit system; }; + }); + templ = system: inputs.templ.packages.${system}.templ; + in { + packages = forAllSystems ({ pkgs, system }: { + myNewPackage = pkgs.buildGoModule { + ... + preBuild = '' + ${templ system}/bin/templ generate + ''; + }; + }); + + devShell = forAllSystems ({ pkgs, system }: + pkgs.mkShell { + buildInputs = with pkgs; [ + go + (templ system) + ]; + }; + }); +} +``` + +## Docker + +A Docker container is pushed on each release to https://github.com/a-h/templ/pkgs/container/templ + +Pull the latest version with: + +```bash +docker pull ghcr.io/a-h/templ:latest +``` + +To use the container, mount the source code of your application into the `/app` directory, set the working directory to the same directory and run `templ generate`, e.g. in a Linux or Mac shell, you can generate code for the current directory with: + +```bash +docker run -v `pwd`:/app -w=/app ghcr.io/a-h/templ:latest generate +``` + +If you want to build templates using a multi-stage Docker build, you can use the `templ` image as a base image. + +Here's an example multi-stage Dockerfile. Note that in the `generate-stage` the source code is copied into the container, and the `templ generate` command is run. The `build-stage` then copies the generated code into the container and builds the application. + +The permissions of the source code are set to a user with a UID of 65532, which is the UID of the `nonroot` user in the `ghcr.io/a-h/templ:latest` image. + +Note also the use of the `RUN ["templ", "generate"]` command instead of the common `RUN templ generate` command. This is because the templ Docker container does not contain a shell environment to keep its size minimal, so the command must be ran in the ["exec" form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form). + +```Dockerfile +# Fetch +FROM golang:latest AS fetch-stage +COPY go.mod go.sum /app +WORKDIR /app +RUN go mod download + +# Generate +FROM ghcr.io/a-h/templ:latest AS generate-stage +COPY --chown=65532:65532 . /app +WORKDIR /app +RUN ["templ", "generate"] + +# Build +FROM golang:latest AS build-stage +COPY --from=generate-stage /app /app +WORKDIR /app +RUN CGO_ENABLED=0 GOOS=linux go build -o /app/app + +# Test +FROM build-stage AS test-stage +RUN go test -v ./... + +# Deploy +FROM gcr.io/distroless/base-debian12 AS deploy-stage +WORKDIR / +COPY --from=build-stage /app/app /app +EXPOSE 8080 +USER nonroot:nonroot +ENTRYPOINT ["/app"] +``` diff --git a/templ/docs/docs/02-quick-start/02-creating-a-simple-templ-component.md b/templ/docs/docs/02-quick-start/02-creating-a-simple-templ-component.md new file mode 100644 index 0000000..cecb782 --- /dev/null +++ b/templ/docs/docs/02-quick-start/02-creating-a-simple-templ-component.md @@ -0,0 +1,85 @@ +# Creating a simple templ component + +To create a templ component, first create a new Go project. + +## Setup project + +Create a new directory containing our project. + +```bash +mkdir hello-world +``` + +Initialize a new Go project within it. + +```bash +cd hello-world +go mod init github.com/a-h/templ-examples/hello-world +go get github.com/a-h/templ +``` + +## Create a templ file + +To use it, create a `hello.templ` file containing a component. + +Components are functions that contain templ elements, markup, and `if`, `switch`, and `for` Go expressions. + +```templ title="hello.templ" +package main + +templ hello(name string) { +
Hello, { name }
+} +``` + +## Generate Go code from the templ file + +Run the `templ generate` command. + +```bash +templ generate +``` + +templ will generate a `hello_templ.go` file containing Go code. + +This file will contain a function called `hello` which takes `name` as an argument, and returns a `templ.Component` that renders HTML. + +```go +func hello(name string) templ.Component { + // ... +} +``` + +## Write a program that renders to stdout + +Create a `main.go` file. + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + component := hello("John") + component.Render(context.Background(), os.Stdout) +} +``` + +## Run the program + +Running the code will render the component's HTML to stdout. + +```bash +go run . +``` + +```html title="Output" +
Hello, John
+``` + +Instead of passing `os.Stdout` to the component's render function, you can pass any type that implements the `io.Writer` interface. This includes files, `bytes.Buffer`, and HTTP responses. + +In this way, templ can be used to generate HTML files that can be hosted as static content in an S3 bucket, Google Cloud Storage, or used to generate HTML that is fed into PDF conversion processes, or sent via email. diff --git a/templ/docs/docs/02-quick-start/03-running-your-first-templ-application.md b/templ/docs/docs/02-quick-start/03-running-your-first-templ-application.md new file mode 100644 index 0000000..b2ceb7a --- /dev/null +++ b/templ/docs/docs/02-quick-start/03-running-your-first-templ-application.md @@ -0,0 +1,47 @@ +# Running your first templ application + +Let's update the previous application to serve HTML over HTTP instead of writing it to the terminal. + +## Create a web server + +Update the `main.go` file. + +templ components can be served as a standard HTTP handler using the `templ.Handler` function. + +```go title="main.go" +package main + +import ( + "fmt" + "net/http" + + "github.com/a-h/templ" +) + +func main() { + component := hello("John") + + http.Handle("/", templ.Handler(component)) + + fmt.Println("Listening on :3000") + http.ListenAndServe(":3000", nil) +} +``` + +## Run the program + +Running the code will start a web server on port 3000. + +```bash +go run *.go +``` + +If you run another terminal session and run `curl` you can see the exact HTML that is returned matches the `hello` component, with the name "John". + +```bash +curl localhost:3000 +``` + +```html name="Output" +
Hello, John
+``` diff --git a/templ/docs/docs/02-quick-start/_category_.json b/templ/docs/docs/02-quick-start/_category_.json new file mode 100644 index 0000000..9bbec13 --- /dev/null +++ b/templ/docs/docs/02-quick-start/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 2, + "label": "Quick start" +} diff --git a/templ/docs/docs/03-syntax-and-usage/01-basic-syntax.md b/templ/docs/docs/03-syntax-and-usage/01-basic-syntax.md new file mode 100644 index 0000000..6cd7b61 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/01-basic-syntax.md @@ -0,0 +1,48 @@ +# Basic syntax + +## Package name and imports + +templ files start with a package name, followed by any required imports, just like Go. + +```go +package main + +import "fmt" +import "time" +``` + +## Components + +templ files can also contain components. Components are markup and code that is compiled into functions that return a `templ.Component` interface by running the `templ generate` command. + +Components can contain templ elements that render HTML, text, expressions that output text or include other templates, and branching statements such as `if` and `switch`, and `for` loops. + +```templ name="header.templ" +package main + +templ headerTemplate(name string) { +
+

{ name }

+
+} +``` + +## Go code + +Outside of templ Components, templ files are ordinary Go code. + +```templ name="header.templ" +package main + +// Ordinary Go code that we can use in our Component. +var greeting = "Welcome!" + +// templ Component +templ headerTemplate(name string) { +
+

{ name }

+

"{ greeting }" comes from ordinary Go code

+
+} +``` + diff --git a/templ/docs/docs/03-syntax-and-usage/02-elements.md b/templ/docs/docs/03-syntax-and-usage/02-elements.md new file mode 100644 index 0000000..3ef67c7 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/02-elements.md @@ -0,0 +1,81 @@ +# Elements + +templ elements are used to render HTML within templ components. + +```templ title="button.templ" +package main + +templ button(text string) { + +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + button("Click me").Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" + +``` + +:::info +templ automatically minifies HTML responses, output is shown formatted for readability. +::: + +## Tags must be closed + +Unlike HTML, templ requires that all HTML elements are closed with either a closing tag (``), or by using a self-closing element (`
`). + +templ is aware of which HTML elements are "void", and will not include the closing `/` in the output HTML. + +```templ title="button.templ" +package main + +templ component() { +
Test
+ +
+} +``` + +```templ title="Output" +
Test
+ +
+``` + +## Attributes and elements can contain expressions + +templ elements can contain placeholder expressions for attributes and content. + +```templ title="button.templ" +package main + +templ button(name string, content string) { + +} +``` + +Rendering the component to stdout, we can see the results. + +```go title="main.go" +func main() { + component := button("John", "Say Hello") + component.Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" + +``` diff --git a/templ/docs/docs/03-syntax-and-usage/03-attributes.md b/templ/docs/docs/03-syntax-and-usage/03-attributes.md new file mode 100644 index 0000000..f2c6b75 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/03-attributes.md @@ -0,0 +1,256 @@ +# Attributes + +## Constant attributes + +templ elements can have HTML attributes that use the double quote character `"`. + +```templ +templ component() { +

Text

+} +``` + +```html title="Output" +

Text

+``` + +## String expression attributes + +Element attributes can be set to Go strings. + +```templ +templ component(testID string) { +

Text

+} + +templ page() { + @component("testid-123") +} +``` + +Rendering the `page` component results in: + +```html title="Output" +

Text

+``` + +:::note +String values are automatically HTML attribute encoded. This is a security measure, but may make the values (especially JSON appear) look strange to you, since some characters may be converted into HTML entities. However, it is correct HTML and won't affect the behavior. +::: + +It's also possible to use function calls in string attribute expressions. + +Here's a function that returns a string based on a boolean input. + +```go +func testID(isTrue bool) string { + if isTrue { + return "testid-123" + } + return "testid-456" +} +``` + +```templ +templ component() { +

Text

+} +``` + +The result: + +```html title="Output" +

Text

+``` + +Functions in string attribute expressions can also return errors. + +```go +func testID(isTrue bool) (string, error) { + if isTrue { + return "testid-123", nil + } + return "", fmt.Errorf("isTrue is false") +} +``` + +If the function returns an error, the `Render` method will return the error along with its location. + +## Boolean attributes + +Boolean attributes (see https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes) where the presence of an attribute name without a value means true, and the attribute name not being present means false are supported. + +```templ +templ component() { +
+} +``` + +```html title="Output" +
+``` + +:::note +templ is aware that `
` is a void element, and renders `
` instead. +::: + + +To set boolean attributes using variables or template parameters, a question mark after the attribute name is used to denote that the attribute is boolean. + +```templ +templ component() { +
+} +``` + +```html title="Output" +
+``` + +## Conditional attributes + +Use an `if` statement within a templ element to optionally add attributes to elements. + +```templ +templ component() { +
+} +``` + +```html title="Output" +
+``` + +## Spread attributes + +Use the `{ attrMap... }` syntax in the open tag of an element to append a dynamic map of attributes to the element's attributes. + +It's possible to spread any variable of type `templ.Attributes`. `templ.Attributes` is a `map[string]any` type definition. + +* If the value is a `string`, the attribute is added with the string value, e.g. `
`. +* If the value is a `bool`, the attribute is added as a boolean attribute if the value is true, e.g. `
`. +* If the value is a `templ.KeyValue[string, bool]`, the attribute is added if the boolean is true, e.g. `
`. +* If the value is a `templ.KeyValue[bool, bool]`, the attribute is added if both boolean values are true, as `
`. + +```templ +templ component(shouldBeUsed bool, attrs templ.Attributes) { +

Text

+
+} + +templ usage() { + @component(false, templ.Attributes{"data-testid": "paragraph"}) +} +``` + +```html title="Output" +

Text

+
+``` + +## URL attributes + +The `` element's `href` attribute is treated differently. templ expects you to provide a `templ.SafeURL` instead of a `string`. + +Typically, you would do this by using the `templ.URL` function. + +The `templ.URL` function sanitizes input URLs and checks that the protocol is `http`/`https`/`mailto` rather than `javascript` or another unexpected protocol. + +```templ +templ component(p Person) { + { strings.ToUpper(p.Name) } +} +``` + +:::tip +In templ, all attributes are HTML-escaped. This means that: + +- `&` characters in the URL are escaped to `&`. +- `"` characters are escaped to `"`. +- `'` characters are escaped to `'`. + +This done to prevent XSS attacks. For example, without escaping, if a string contained `http://google.com" onclick="alert('hello')"`, the browser would interpret this as a URL followed by an `onclick` attribute, which would execute JavaScript code. + +The escaping does not change the URL's functionality. + +Sanitization is the process of examining the URL scheme (protocol) and structure to ensure that it's safe to use, e.g. that it doesn't contain `javascript:` or other potentially harmful schemes. If a URL is not safe, templ will replace the URL with `about:invalid#TemplFailedSanitizationURL`. +::: + +The `templ.URL` function only supports standard HTML elements and attributes (` + { contact.Name } +
+} +``` + +:::caution +If you need to bypass this sanitization, you can use `templ.SafeURL(myURL)` to mark that your string is safe to use. + +This may introduce security vulnerabilities to your program. +::: + +## JavaScript attributes + +`onClick` and other `on*` handlers have special behaviour, they expect a reference to a `script` template. + +:::info +This ensures that any client-side JavaScript that is required for a component to function is only emitted once, that script name collisions are not possible, and that script input parameters are properly sanitized. +::: + +```templ +script withParameters(a string, b string, c int) { + console.log(a, b, c); +} + +script withoutParameters() { + alert("hello"); +} + +templ Button(text string) { + +} +``` + +```html title="Output" + + +``` + +## CSS attributes + +CSS handling is discussed in detail in [CSS style management](/syntax-and-usage/css-style-management). + +## JSON attributes + +To set an attribute's value to a JSON string (e.g. for HTMX's [hx-vals](https://htmx.org/attributes/hx-vals) or Alpine's [x-data](https://alpinejs.dev/directives/data)), serialize the value to a string using a function. + +```go +func countriesJSON() string { + countries := []string{"Czech Republic", "Slovakia", "United Kingdom", "Germany", "Austria", "Slovenia"} + bytes, _ := json.Marshal(countries) + return string(bytes) +} +``` + +```templ +templ SearchBox() { + +} +``` diff --git a/templ/docs/docs/03-syntax-and-usage/04-expressions.md b/templ/docs/docs/03-syntax-and-usage/04-expressions.md new file mode 100644 index 0000000..22b840e --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/04-expressions.md @@ -0,0 +1,103 @@ +# Expressions + +## String expressions + +Within a templ element, expressions can be used to render strings. Content is automatically escaped using context-aware HTML encoding rules to protect against XSS and CSS injection attacks. + +String literals, variables and functions that return a string can be used. + +### Literals + +You can use Go string literals. + +```templ title="component.templ" +package main + +templ component() { +
{ "print this" }
+
{ `and this` }
+} +``` + +```html title="Output" +
print this
and this
+``` + +### Variables + +Any Go string variable can be used, for example: + +* A string function parameter. +* A field on a struct. +* A variable or constant string that is in scope. + +```templ title="/main.templ" +package main + +templ greet(prefix string, p Person) { +
{ prefix } { p.Name }{ exclamation }
+} +``` + +```templ title="main.go" +package main + +type Person struct { + Name string +} + +const exclamation = "!" + +func main() { + p := Person{ Name: "John" } + component := greet("Hello", p) + component.Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" +
Hello John!
+``` + +### Functions + +Functions that return `string` or `(string, error)` can be used. + +```templ title="component.templ" +package main + +import "strings" +import "strconv" + +func getString() (string, error) { + return "DEF", nil +} + +templ component() { +
{ strings.ToUpper("abc") }
+
{ getString() }
+} +``` + +```html title="Output" +
ABC
+
DEF
+``` + +If the function returns an error, the `Render` function will return an error containing the location of the error and the underlying error. + +### Escaping + +templ automatically escapes strings using HTML escaping rules. + +```templ title="component.templ" +package main + +templ component() { +
{ `
` }
+} +``` + +```html title="Output" +
</div><script>alert('hello!')</script><div>
+``` diff --git a/templ/docs/docs/03-syntax-and-usage/05-statements.md b/templ/docs/docs/03-syntax-and-usage/05-statements.md new file mode 100644 index 0000000..3e80f2b --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/05-statements.md @@ -0,0 +1,101 @@ +# Statements + +## Control flow + +Within a templ element, a subset of Go statements can be used directly. + +These Go statements can be used to conditionally render child elements, or to iterate variables. + +For individual implementation guides see: + +* [if/else](/syntax-and-usage/if-else) +* [switch](/syntax-and-usage/switch) +* [for loops](/syntax-and-usage/loops) + +## if/switch/for within text + +Go statements can be used without any escaping to make it simple for developers to include them. + +The templ parser assumes that text that starts with `if`, `switch` or `for` denotes the start of one of those expressions as per this example. + +```templ title="show-hello.templ" +package main + +templ showHelloIfTrue(b bool) { +
+ if b { +

Hello

+ } +
+} +``` + +If you need to start a text block with the words `if`, `switch`, or `for`: + +* Use a Go string expression. +* Capitalise `if`, `switch`, or `for`. + +```templ title="paragraph.templ" +package main + +templ display(price float64, count int) { +

Switch to Linux

+

{ `switch to Linux` }

+

{ "for a day" }

+

{ fmt.Sprintf("%f", price) }{ "for" }{ fmt.Sprintf("%d", count) }

+

{ fmt.Sprintf("%f for %d", price, count) }

+} +``` + +## Design considerations + +We decided to not require a special prefix for `if`, `switch` and `for` expressions on the basis that we were more likely to want to use a Go control statement than start a text run with those strings. + +To reduce the risk of a broken control statement, resulting in printing out the source code of the application, templ will complain if a text run starts with `if`, `switch` or `for`, but no opening brace `{` is found. + +For example, the following code causes the templ parser to return an error: + +```templ title="broken-if.templ" +package main + +templ showIfTrue(b bool) { + if b +

Hello

+ } +} +``` + +:::note +Note the missing `{` on line 4. +::: + +The following code also produces an error, since the text run starts with `if`, but no opening `{` is found. + +```templ title="paragraph.templ" +package main + +templ text(b bool) { +

if a tree fell in the woods

+} +``` + +:::note +This also applies to `for` and `switch` statements. +::: + +To resolve the issue: + +* Use a Go string expression. +* Capitalise `if`, `switch`, or `for`. + +```templ title="paragraph.templ" +package main + +templ display(price float64, count int) { +

Switch to Linux

+

{ `switch to Linux` }

+

{ "for a day" }

+

{ fmt.Sprintf("%f", price) }{ "for" }{ fmt.Sprintf("%d", count) }

+

{ fmt.Sprintf("%f for %d", price, count) }

+} +``` diff --git a/templ/docs/docs/03-syntax-and-usage/06-if-else.md b/templ/docs/docs/03-syntax-and-usage/06-if-else.md new file mode 100644 index 0000000..3d633d5 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/06-if-else.md @@ -0,0 +1,32 @@ +# If/else + +templ uses standard Go `if`/`else` statements which can be used to conditionally render components and elements. + +```templ title="component.templ" +templ login(isLoggedIn bool) { + if isLoggedIn { +
Welcome back!
+ } else { + + } +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + login(true).Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" +
+ Welcome back! +
+``` diff --git a/templ/docs/docs/03-syntax-and-usage/07-switch.md b/templ/docs/docs/03-syntax-and-usage/07-switch.md new file mode 100644 index 0000000..92002f6 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/07-switch.md @@ -0,0 +1,37 @@ +# Switch + +templ uses standard Go `switch` statements which can be used to conditionally render components and elements. + +```templ title="component.templ" +package main + +templ userTypeDisplay(userType string) { + switch userType { + case "test": + { "Test user" } + case "admin": + { "Admin user" } + default: + { "Unknown user" } + } +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + userTypeDisplay("Other").Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" + + Unknown user + +``` diff --git a/templ/docs/docs/03-syntax-and-usage/08-loops.md b/templ/docs/docs/03-syntax-and-usage/08-loops.md new file mode 100644 index 0000000..85bed0e --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/08-loops.md @@ -0,0 +1,23 @@ +# For loops + +Use the standard Go `for` loop for iteration. + +```templ title="component.templ" +package main + +templ nameList(items []Item) { +
    + for _, item := range items { +
  • { item.Name }
  • + } +
+} +``` + +```html title="Output" +
    +
  • A
  • +
  • B
  • +
  • C
  • +
+``` diff --git a/templ/docs/docs/03-syntax-and-usage/09-raw-go.md b/templ/docs/docs/03-syntax-and-usage/09-raw-go.md new file mode 100644 index 0000000..56302db --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/09-raw-go.md @@ -0,0 +1,24 @@ +# Raw Go + +For some more advanced use cases it may be useful to write Go code statements in your template. + +Use the `{{ ... }}` syntax for this. + +## Variable declarations + +Scoped variables can be created using this syntax, to reduce the need for multiple function calls. + +```templ title="component.templ" +package main + +templ nameList(items []Item) { + {{ first := items[0] }} +

+ { first.Name } +

+} +``` + +```html title="Output" +

A

+``` diff --git a/templ/docs/docs/03-syntax-and-usage/10-template-composition.md b/templ/docs/docs/03-syntax-and-usage/10-template-composition.md new file mode 100644 index 0000000..6ce08fd --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/10-template-composition.md @@ -0,0 +1,320 @@ +# Template composition + +Templates can be composed using the import expression. + +```templ +templ showAll() { + @left() + @middle() + @right() +} + +templ left() { +
Left
+} + +templ middle() { +
Middle
+} + +templ right() { +
Right
+} +``` + +```html title="Output" +
+ Left +
+
+ Middle +
+
+ Right +
+``` + +## Children + +Children can be passed to a component for it to wrap. + +```templ +templ showAll() { + @wrapChildren() { +
Inserted from the top
+ } +} + +templ wrapChildren() { +
+ { children... } +
+} +``` + +:::note +The use of the `{ children... }` expression in the child component. +::: + +```html title="output" +
+
+ Inserted from the top +
+
+``` + +### Using children in code components + +Children are passed to a component using the Go context. To pass children to a component using Go code, use the `templ.WithChildren` function. + +```templ +package main + +import ( + "context" + "os" + + "github.com/a-h/templ" +) + +templ wrapChildren() { +
+ { children... } +
+} + +func main() { + contents := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + _, err := io.WriteString(w, "
Inserted from Go code
") + return err + }) + ctx := templ.WithChildren(context.Background(), contents) + wrapChildren().Render(ctx, os.Stdout) +} +``` + +```html title="output" +
+
+ Inserted from Go code +
+
+``` + +To get children from the context, use the `templ.GetChildren` function. + +```templ +package main + +import ( + "context" + "os" + + "github.com/a-h/templ" +) + +func main() { + contents := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + _, err := io.WriteString(w, "
Inserted from Go code
") + return err + }) + wrapChildren := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + children := templ.GetChildren(ctx) + ctx = templ.ClearChildren(ctx) + _, err := io.WriteString(w, "
") + if err != nil { + return err + } + err = children.Render(ctx, w) + if err != nil { + return err + } + _, err = io.WriteString(w, "
") + return err + }) +``` + +:::note +The `templ.ClearChildren` function is used to stop passing the children down the tree. +::: + +## Components as parameters + +Components can also be passed as parameters and rendered using the `@component` expression. + +```templ +package main + +templ heading() { +

Heading

+} + +templ layout(contents templ.Component) { +
+ @heading() +
+
+ @contents +
+} + +templ paragraph(contents string) { +

{ contents }

+} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + c := paragraph("Dynamic contents") + layout(c).Render(context.Background(), os.Stdout) +} +``` + +```html title="output" +
+

Heading

+
+
+

Dynamic contents

+
+``` + +You can pass `templ` components as parameters to other components within templates using standard Go function call syntax. + +```templ +package main + +templ heading() { +

Heading

+} + +templ layout(contents templ.Component) { +
+ @heading() +
+
+ @contents +
+} + +templ paragraph(contents string) { +

{ contents }

+} + +templ root() { + @layout(paragraph("Dynamic contents")) +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + root().Render(context.Background(), os.Stdout) +} +``` + +```html title="output" +
+

Heading

+
+
+

Dynamic contents

+
+``` + +## Joining Components + +Components can be aggregated into a single Component using `templ.Join`. + +```templ +package main + +templ hello() { + hello +} + +templ world() { + world +} + +templ helloWorld() { + @templ.Join(hello(), world()) +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + helloWorld().Render(context.Background(), os.Stdout) +} +``` + +```html title="output" +helloworld +``` + +## Sharing and re-using components + +Since templ components are compiled into Go functions by the `go generate` command, templ components follow the rules of Go, and are shared in exactly the same way as Go code. + +templ files in the same directory can access each other's components. Components in different directories can be accessed by importing the package that contains the component, so long as the component is exported by capitalizing its name. + +:::tip +In Go, a _package_ is a collection of Go source files in the same directory that are compiled together. All of the functions, types, variables, and constants defined in one source file in a package are available to all other source files in the same package. + +Packages exist within a Go _module_, defined by the `go.mod` file. +::: + +:::note +Go is structured differently to JavaScript, but uses similar terminology. A single `.js` or `.ts` _file_ is like a Go package, and an NPM package is like a Go module. +::: + +### Exporting components + +To make a templ component available to other packages, export it by capitalizing its name. + +```templ +package components + +templ Hello() { +
Hello
+} +``` + +### Importing components + +To use a component in another package, import the package and use the component as you would any other Go function or type. + +```templ +package main + +import "github.com/a-h/templ/examples/counter/components" + +templ Home() { + @components.Hello() +} +``` + +:::tip +To import a component from another Go module, you must first import the module by using the `go get ` command. Then, you can import the component as you would any other Go package. +::: diff --git a/templ/docs/docs/03-syntax-and-usage/11-css-style-management.md b/templ/docs/docs/03-syntax-and-usage/11-css-style-management.md new file mode 100644 index 0000000..4362302 --- /dev/null +++ b/templ/docs/docs/03-syntax-and-usage/11-css-style-management.md @@ -0,0 +1,448 @@ +# CSS style management + +## HTML class and style attributes + +The standard HTML `class` and `style` attributes can be added to components. Note the use of standard quotes to denote a static value. + +```templ +templ button(text string) { + +} +``` + +```html title="Output" + +``` + +## Style attribute + +To use a variable in the style attribute, use braces to denote the Go expression. + +```templ +templ button(style, text string) { + +} +``` + +You can pass multiple values to the `style` attribute. The results are all added to the output. + +```templ +templ button(style1, style2 string, text string) { + +} +``` + +The style attribute supports use of the following types: + +* `string` - A string containing CSS properties, e.g. `background-color: red`. +* `templ.SafeCSS` - A value containing CSS properties and values that will not be sanitized, e.g. `background-color: red; text-decoration: underline` +* `map[string]string` - A map of string keys to string values, e.g. `map[string]string{"color": "red"}` +* `map[string]templ.SafeCSSProperty` - A map of string keys to values, where the values will not be sanitized. +* `templ.KeyValue[string, string]` - A single CSS key/value. +* `templ.KeyValue[string, templ.SafeCSSProperty` - A CSS key/value, but the value will not be sanitized. +* `templ.KeyValue[string, bool]` - A map where the CSS in the key is only included in the output if the boolean value is true. +* `templ.KeyValue[templ.SafeCSS, bool]` - A map where the CSS in the key is only included if the boolean value is true. + +Finally, a function value that returns any of the above types can be used. + +Go syntax allows you to pass a single function that returns a value and an error. + +```templ +templ Page(userType string) { +
Styled
+} + +func getStyle(userType string) (string, error) { + //TODO: Look up in something that might error. + return "background-color: red", errors.New("failed") +} +``` + +Or multiple functions and values that return a single type. + +```templ +templ Page(userType string) { +
Styled
+} + +func getStyle(userType string) (string) { + return "background-color: red" +} +``` + +### Style attribute examples + +#### Maps + +Maps are useful when styles need to be dynamically computed based on component state or external inputs. + +```templ +func getProgressStyle(percent int) map[string]string { + return map[string]string{ + "width": fmt.Sprintf("%d%%", percent), + "transition": "width 0.3s ease", + } +} + +templ ProgressBar(percent int) { +
+
+
+} +``` + +```html title="Output (percent=75)" +
+
+
+``` + +#### KeyValue pattern + +The `templ.KV` helper provides conditional style application in a more compact syntax. + +```templ +templ TextInput(value string, hasError bool) { + +} +``` + +```html title="Output (hasError=true)" + +``` + +#### Bypassing sanitization + +By default, dynamic CSS values are sanitized to protect against dangerous CSS values that might introduce vulnerabilities into your application. + +However, if you're sure, you can bypass sanitization by marking your content as safe with the `templ.SafeCSS` and `templ.SafeCSSProperty` types. + +```templ +func calculatePositionStyles(x, y int) templ.SafeCSS { + return templ.SafeCSS(fmt.Sprintf( + "transform: translate(%dpx, %dpx);", + x*2, // Example calculation + y*2, + )) +} + +templ DraggableElement(x, y int) { +
+ Drag me +
+} +``` + +```html title="Output (x=10, y=20)" +
+ Drag me +
+``` + +### Pattern use cases + +| Pattern | Best For | Example Use Case | +|---------|----------|------------------| +| **Maps** | Dynamic style sets requiring multiple computed values | Progress indicators, theme switching | +| **KeyValue** | Conditional style toggling | Form validation, interactive states | +| **Functions** | Complex style generation | Animations, data visualizations | +| **Direct Strings** | Simple static styles | Basic formatting, utility classes | + +### Sanitization behaviour + +By default, dynamic CSS values are sanitized to protect against dangerous CSS values that might introduce vulnerabilities into your application. + +```templ +templ UnsafeExample() { +
+ Dangerous content +
+} +``` + +```html title="Output" +
+ Dangerous content +
+``` + +These protections can be bypassed with the `templ.SafeCSS` and `templ.SafeCSSProperty` types. + +```templ +templ SafeEmbed() { +
+ Trusted content +
+} +``` + +```html title="Output" +
+ Trusted content +
+``` + +:::note +HTML attribute escaping is not bypassed, so `<`, `>`, `&` and quotes will always appear as HTML entities (`<` etc.) in attributes - this is good practice, and doesn't affect how browsers use the CSS. +::: + +### Error Handling + +Invalid values are automatically sanitized: + +```templ +templ InvalidButton() { + +} +``` + +```html title="Output" + +``` + +Go's type system doesn't support union types, so it's not possible to limit the inputs to the style attribute to just the supported types. + +As such, the attribute takes `any`, and executes type checks at runtime. Any invalid types will produce the CSS value `zTemplUnsupportedStyleAttributeValue:Invalid;`. + +## Class attributes + +To use a variable as the name of a CSS class, use a CSS expression. + +```templ title="component.templ" +package main + +templ button(text string, className string) { + +} +``` + +The class expression can take an array of values. + +```templ title="component.templ" +package main + +templ button(text string, className string) { + +} +``` + +### Dynamic class names + +Toggle addition of CSS classes to an element based on a boolean value by passing: + +* A `string` containing the name of a class to apply. +* A `templ.KV` value containing the name of the class to add to the element, and a boolean that determines whether the class is added to the attribute at render time. + * `templ.KV("is-primary", true)` + * `templ.KV("hover:red", true)` +* A map of string class names to a boolean that determines if the class is added to the class attribute value at render time: + * `map[string]bool` + * `map[CSSClass]bool` + +```templ title="component.templ" +package main + +css red() { + background-color: #ff0000; +} + +templ button(text string, isPrimary bool) { + +} +``` + +```go title="main.go" +package main + +import ( + "context" + "os" +) + +func main() { + button("Click me", false).Render(context.Background(), os.Stdout) +} +``` + +```html title="Output" + +``` + +## CSS elements + +The standard ` +

+ Paragraph contents. +

+} +``` + +```html title="Output" + +

+ Paragraph contents. +

+``` + +:::tip +If you want to make sure that the CSS element is only output once, even if you use a template many times, use a CSS expression. +::: + +## CSS components + +When developing a component library, it may not be desirable to require that specific CSS classes are present when the HTML is rendered. + +There may be CSS class name clashes, or developers may forget to include the required CSS. + +To include CSS within a component library, use a CSS component. + +CSS components can also be conditionally rendered. + +```templ title="component.templ" +package main + +var red = "#ff0000" +var blue = "#0000ff" + +css primaryClassName() { + background-color: #ffffff; + color: { red }; +} + +css className() { + background-color: #ffffff; + color: { blue }; +} + +templ button(text string, isPrimary bool) { + +} +``` + +```html title="Output" + + +``` + +:::info +The CSS class is given a unique name the first time it is used, and only rendered once per HTTP request to save bandwidth. +::: + +:::caution +The class name is autogenerated, don't rely on it being consistent. +::: + +### CSS component arguments + +CSS components can also require function arguments. + +```templ title="component.templ" +package main + +css loading(percent int) { + width: { fmt.Sprintf("%d%%", percent) }; +} + +templ index() { +
+
+} +``` + +```html title="Output" + +
+ +
+``` + +### CSS Sanitization + +To prevent CSS injection attacks, templ automatically sanitizes dynamic CSS property names and values using the `templ.SanitizeCSS` function. Internally, this uses a lightweight fork of Google's `safehtml` package to sanitize the value. + +If a property name or value has been sanitized, it will be replaced with `zTemplUnsafeCSSPropertyName` for property names, or `zTemplUnsafeCSSPropertyValue` for property values. + +To bypass this sanitization, e.g. for URL values of `background-image`, you can mark the value as safe using the `templ.SafeCSSProperty` type. + +```templ +css windVaneRotation(degrees float64) { + transform: { templ.SafeCSSProperty(fmt.Sprintf("rotate(%ddeg)", int(math.Round(degrees)))) }; +} + +templ Rotate(degrees float64) { +
Rotate
+} +``` + +### CSS Middleware + +The use of CSS templates means that ` +} +``` + +`onClick` attributes, and other `on*` attributes are used to execute JavaScript. To prevent user data from being unescaped, `on*` attributes accept a `templ.ComponentScript`. + +```html +script onClickHandler(msg string) { + alert(msg); +} + +templ Example(msg string) { +
+ { "will be HTML encoded using templ.Escape" } +
+} +``` + +Style attributes cannot be expressions, only constants, to avoid escaping vulnerabilities. templ style templates (`css className()`) should be used instead. + +```html +templ Example() { +
+} +``` + +Class names are sanitized by default. A failed class name is replaced by `--templ-css-class-safe-name`. The sanitization can be bypassed using the `templ.SafeClass` function, but the result is still subject to escaping. + +```html +templ Example() { +
+} +``` + +Rendered output: + +```html +
+``` + +```html +templ Example() { +
Node text is not modified at all.
+
{ "will be escaped using templ.EscapeString" }
+} +``` + +`href` attributes must be a `templ.SafeURL` and are sanitized to remove JavaScript URLs unless bypassed. + +```html +templ Example() { +
Text + + +} +``` + +Within css blocks, property names, and constant CSS property values are not sanitized or escaped. + +```css +css className() { + background-color: #ffffff; +} +``` + +CSS property values based on expressions are passed through `templ.SanitizeCSS` to replace potentially unsafe values with placeholders. + +```css +css className() { + color: { red }; +} +``` diff --git a/templ/docs/docs/10-security/02-content-security-policy.md b/templ/docs/docs/10-security/02-content-security-policy.md new file mode 100644 index 0000000..36a9e58 --- /dev/null +++ b/templ/docs/docs/10-security/02-content-security-policy.md @@ -0,0 +1,86 @@ +# Content security policy + +## Nonces + +In templ [script templates](/syntax-and-usage/script-templates#script-templates) are rendered as inline ` + +``` diff --git a/templ/docs/docs/10-security/03-code-signing.md b/templ/docs/docs/10-security/03-code-signing.md new file mode 100644 index 0000000..c6cfb75 --- /dev/null +++ b/templ/docs/docs/10-security/03-code-signing.md @@ -0,0 +1,7 @@ +# Code signing + +Binaries are created by the GitHub Actions workflow at https://github.com/a-h/templ/blob/main/.github/workflows/release.yml + +Binaries are signed by cosign. The public key is stored in the repository at https://github.com/a-h/templ/blob/main/cosign.pub + +Instructions for key verification at https://docs.sigstore.dev/verifying/verify/ diff --git a/templ/docs/docs/10-security/_category_.json b/templ/docs/docs/10-security/_category_.json new file mode 100644 index 0000000..0132b3b --- /dev/null +++ b/templ/docs/docs/10-security/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 10, + "label": "Security" +} diff --git a/templ/docs/docs/11-media/_category_.json b/templ/docs/docs/11-media/_category_.json new file mode 100644 index 0000000..d817bf6 --- /dev/null +++ b/templ/docs/docs/11-media/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 11, + "label": "Media and talks" +} diff --git a/templ/docs/docs/11-media/index.md b/templ/docs/docs/11-media/index.md new file mode 100644 index 0000000..98a1a7b --- /dev/null +++ b/templ/docs/docs/11-media/index.md @@ -0,0 +1,33 @@ +# Media and talks + +# Go Podcast 2024 + +https://gopodcast.dev/episodes/adrian-hesketh-and-joe-davidson-on-templ + +# Gophercon 2024 + +Go Full Stack Server-Side Rendering vs SPAs - Fernando J. Villamarin Diaz, JPMC + + + +# Big Sky Dev Con 2024 + +Covers the reason for creating templ, how it works, and how to use it. + + + +# Go Time + +

Go Time 291: Go templating using Templ – Listen on Changelog.com

+ +# Gophercon UK 2023 + +This talk covers Language Server Protocol from the ground up, and how templ's language server works with gopls. + + + +# How To Setup A Golang + Templ Project Structure + +This tutorial shows how to create a simple web app using templ and the echo router. + + diff --git a/templ/docs/docs/12-integrations/01-web-frameworks.md b/templ/docs/docs/12-integrations/01-web-frameworks.md new file mode 100644 index 0000000..69ad4be --- /dev/null +++ b/templ/docs/docs/12-integrations/01-web-frameworks.md @@ -0,0 +1,106 @@ +# Web frameworks + +Templ is framework agnostic but that does not mean it can not be used with Go frameworks and other tools. + +Below are some examples of how to use templ with other Go libraries, frameworks and tools, and links to systems that have built-in templ support. + +### Chi + +See an example of using https://github.com/go-chi/chi with templ at: + +https://github.com/a-h/templ/tree/main/examples/integration-chi + +### Echo + +See an example of using https://echo.labstack.com/ with templ at: + +https://github.com/a-h/templ/tree/main/examples/integration-echo + +### Gin + +See an example of using https://github.com/gin-gonic/gin with templ at: + +https://github.com/a-h/templ/tree/main/examples/integration-gin + +### Go Fiber + +See an example of using https://github.com/gofiber/fiber with templ at: + +https://github.com/a-h/templ/tree/main/examples/integration-gofiber + +### github.com/gorilla/csrf + +`gorilla/csrf` is a HTTP middleware library that provides cross-site request forgery (CSRF) protection. + +Follow the instructions at https://github.com/gorilla/csrf to add it to your project, by using the library as HTTP middleware. + +```go title="main.go" +package main + +import ( + "crypto/rand" + "fmt" + "net/http" + "github.com/gorilla/csrf" +) + +func mustGenerateCSRFKey() (key []byte) { + key = make([]byte, 32) + n, err := rand.Read(key) + if err != nil { + panic(err) + } + if n != 32 { + panic("unable to read 32 bytes for CSRF key") + } + return +} + +func main() { + r := http.NewServeMux() + r.Handle("/", templ.Handler(Form())) + + csrfMiddleware := csrf.Protect(mustGenerateCSRFKey()) + withCSRFProtection := csrfMiddleware(r) + + fmt.Println("Listening on localhost:8000") + http.ListenAndServe("localhost:8000", withCSRFProtection) +} +``` + +Creating a `CSRF` templ component makes it easy to include the CSRF token in your forms. + +```templ title="form.templ" +templ Form() { +

CSRF Example

+
+ @CSRF() +
+ If you inspect the HTML form, you will see a hidden field with the value: { ctx.Value("gorilla.csrf.Token").(string) } +
+ +
+
+
+ You can also submit the form without the CSRF token to validate that the CSRF protection is working. +
+ +
+} + +templ CSRF() { + +} +``` + +## Project scaffolding + +- Gowebly - https://github.com/gowebly/gowebly +- Go-blueprint - https://github.com/Melkeydev/go-blueprint +- Slick - https://github.com/anthdm/slick + +## Other templates + +### `template/html` + +See [Using with Go templates](../syntax-and-usage/using-with-go-templates) diff --git a/templ/docs/docs/12-integrations/02-internationalization.md b/templ/docs/docs/12-integrations/02-internationalization.md new file mode 100644 index 0000000..1443d6f --- /dev/null +++ b/templ/docs/docs/12-integrations/02-internationalization.md @@ -0,0 +1,95 @@ +# Internationalization + +templ can be used with 3rd party internationalization libraries. + +## ctxi18n + +https://github.com/invopop/ctxi18n uses the context package to load strings based on the selected locale. + +An example is available at https://github.com/a-h/templ/tree/main/examples/internationalization + +### Storing translations + +Translations are stored in YAML files, according to the language. + +```yaml title="locales/en/en.yaml" +en: + hello: "Hello" + select_language: "Select Language" +``` + +### Selecting the language + +HTTP middleware selects the language to load based on the URL path, `/en`, `/de`, etc. + +```go title="main.go" +func newLanguageMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lang := "en" // Default language + pathSegments := strings.Split(r.URL.Path, "/") + if len(pathSegments) > 1 { + lang = pathSegments[1] + } + ctx, err := ctxi18n.WithLocale(r.Context(), lang) + if err != nil { + log.Printf("error setting locale: %v", err) + http.Error(w, "error setting locale", http.StatusBadRequest) + return + } + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} +``` + +### Using the middleware + +The `ctxi18n.Load` function is used to load the translations, and the middleware is used to set the language. + +```go title="main.go" +func main() { + if err := ctxi18n.Load(locales.Content); err != nil { + log.Fatalf("error loading locales: %v", err) + } + + mux := http.NewServeMux() + mux.Handle("/", templ.Handler(page())) + + withLanguageMiddleware := newLanguageMiddleware(mux) + + log.Println("listening on :8080") + if err := http.ListenAndServe("127.0.0.1:8080", withLanguageMiddleware); err != nil { + log.Printf("error listening: %v", err) + } +} +``` + +### Fetching translations in templates + +Translations are fetched using the `i18n.T` function, passing the implicit context that's available in all templ components, and the key for the translation. + +```templ +package main + +import ( + "github.com/invopop/ctxi18n/i18n" +) + +templ page() { + + + + + { i18n.T(ctx, "hello") } + + +

{ i18n.T(ctx, "hello") }

+

{ i18n.T(ctx, "select_language") }

+ + + +} +``` diff --git a/templ/docs/docs/12-integrations/_category_.json b/templ/docs/docs/12-integrations/_category_.json new file mode 100644 index 0000000..1040ab5 --- /dev/null +++ b/templ/docs/docs/12-integrations/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 12, + "label": "Integrations" +} diff --git a/templ/docs/docs/13-experimental/01-overview.md b/templ/docs/docs/13-experimental/01-overview.md new file mode 100644 index 0000000..ced20db --- /dev/null +++ b/templ/docs/docs/13-experimental/01-overview.md @@ -0,0 +1,14 @@ +# Experimental packages + +Experimental Packages for templ are available at https://github.com/templ-go/x/ + +:::warning +- Packages in this module are experimental and may be removed at any time. +- There is no guarantee of compatibility with future versions. +- There is no guarantee of stability. +- Use at your own risk. +::: + +## Approval Process + +As of right now, there is no formal approval process for packages to be stabilized and moved into https://github.com/a-h/templ. Feel free to contribute via GitHub discussions at https://github.com/a-h/templ/discussions diff --git a/templ/docs/docs/13-experimental/02-urlbuilder.md b/templ/docs/docs/13-experimental/02-urlbuilder.md new file mode 100644 index 0000000..b3ddf61 --- /dev/null +++ b/templ/docs/docs/13-experimental/02-urlbuilder.md @@ -0,0 +1,31 @@ +# urlbuilder + +A simple URL builder to construct a `templ.SafeURL`. + +```templ title="component.templ" +import ( + "github.com/templ-go/x/urlbuilder" + "strconv" + "strings" +) + +templ component(o Order) { + + { strings.ToUpper(o.Name) } + +} +``` + +See [URL Attributes](/syntax-and-usage/attributes#url-attributes) for more information. + +## Feedback + +Please leave your feedback on this feature at https://github.com/a-h/templ/discussions/867 diff --git a/templ/docs/docs/13-experimental/_category_.json b/templ/docs/docs/13-experimental/_category_.json new file mode 100644 index 0000000..97f2642 --- /dev/null +++ b/templ/docs/docs/13-experimental/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 13, + "label": "Experimental" +} diff --git a/templ/docs/docs/14-help-and-community/_category_.json b/templ/docs/docs/14-help-and-community/_category_.json new file mode 100644 index 0000000..d81ae8d --- /dev/null +++ b/templ/docs/docs/14-help-and-community/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 14, + "label": "Help and community" +} diff --git a/templ/docs/docs/14-help-and-community/index.md b/templ/docs/docs/14-help-and-community/index.md new file mode 100644 index 0000000..d3a2fae --- /dev/null +++ b/templ/docs/docs/14-help-and-community/index.md @@ -0,0 +1,13 @@ +# Getting help + +For help from the community, talking about new ideas, and general discussion: + +## Slack + +Use the #templ channel in the Gopher Slack community. + +https://invite.slack.golangbridge.org/ + +## GitHub Discussion + +https://github.com/a-h/templ/discussions diff --git a/templ/docs/docs/15-faq/_category_.json b/templ/docs/docs/15-faq/_category_.json new file mode 100644 index 0000000..9efb4e8 --- /dev/null +++ b/templ/docs/docs/15-faq/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 15, + "label": "FAQ" +} diff --git a/templ/docs/docs/15-faq/index.md b/templ/docs/docs/15-faq/index.md new file mode 100644 index 0000000..a5f6b25 --- /dev/null +++ b/templ/docs/docs/15-faq/index.md @@ -0,0 +1,7 @@ +# FAQ + +## How can I migrate from templ version 0.1.x to templ 0.2.x syntax? + +Versions of templ <= v0.2.663 include a `templ migrate` command that can migrate v1 syntax to v2. + +The v1 syntax used some extra characters for variable injection, e.g. `{%= name %}` whereas the latest (v2) syntax uses a single pair of braces within HTML, e.g. `{ name }`. diff --git a/templ/docs/docs/go.mod b/templ/docs/docs/go.mod new file mode 100644 index 0000000..f52143e --- /dev/null +++ b/templ/docs/docs/go.mod @@ -0,0 +1,8 @@ +module github.com/a-h/templ/docs + +go 1.20 + +require ( + github.com/gosimple/slug v1.13.1 // indirect + github.com/gosimple/unidecode v1.0.1 // indirect +) diff --git a/templ/docs/docs/go.sum b/templ/docs/docs/go.sum new file mode 100644 index 0000000..b7fc16e --- /dev/null +++ b/templ/docs/docs/go.sum @@ -0,0 +1,4 @@ +github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= +github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= +github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= diff --git a/templ/docs/docs/index.md b/templ/docs/docs/index.md new file mode 100644 index 0000000..7c0acd5 --- /dev/null +++ b/templ/docs/docs/index.md @@ -0,0 +1,30 @@ +--- +sidebar_position: 1 +--- + +# Introduction + +## templ - build HTML with Go + +Create components that render fragments of HTML and compose them to create screens, pages, documents, or apps. + +* Server-side rendering: Deploy as a serverless function, Docker container, or standard Go program. +* Static rendering: Create static HTML files to deploy however you choose. +* Compiled code: Components are compiled into performant Go code. +* Use Go: Call any Go code, and use standard `if`, `switch`, and `for` statements. +* No JavaScript: Does not require any client or server-side JavaScript. +* Great developer experience: Ships with IDE autocompletion. + +```templ +package main + +templ Hello(name string) { +
Hello, { name }
+} + +templ Greeting(person Person) { +
+ @Hello(person.Name) +
+} +``` diff --git a/templ/docs/docs/main.go b/templ/docs/docs/main.go new file mode 100644 index 0000000..67b4225 --- /dev/null +++ b/templ/docs/docs/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/gosimple/slug" +) + +type Section struct { + Name string + SubItems []string +} + +type ItemToCreate struct { + Name string + Path string + IsFile bool + Content string +} + +func main() { + sections := []Section{ + {Name: "Quick Start", SubItems: []string{"Installation", "Creating a simple templ component", "Running your first templ application"}}, + {Name: "Syntax and Usage", SubItems: []string{"Basic syntax", "Expressions", "Conditional HTML attribute expressions", "Loops", "Template composition", "CSS style management"}}, + {Name: "Core Concepts", SubItems: []string{"Components", "Template generation", "Conditional rendering", "Rendering lists", "Code-only components"}}, + {Name: "Components", SubItems: []string{"Creating and organizing components", "Adding HTML markup and Go code in templ", "Configuring components with parameters"}}, + {Name: "Using Go Functions and Variables", SubItems: []string{}}, + {Name: "Server-side Rendering", SubItems: []string{"Creating an HTTP server with templ", "Example: Counter application"}}, + {Name: "Static Rendering", SubItems: []string{"Generating static HTML files with templ", "Deploying static files"}}, + {Name: "Hosting and Deployment", SubItems: []string{"Hosting on AWS Lambda", "Hosting using Docker"}}, + {Name: "Commands and Tools", SubItems: []string{"templ generate", "templ fmt", "templ lsp"}}, + {Name: "Advanced Topics", SubItems: []string{"Code-only components", "Source maps", "Storybook integration"}}, + {Name: "Tutorials and Examples", SubItems: []string{"Tutorial: Counter application", "Tutorial: Blog application"}}, + {Name: "API Reference", SubItems: []string{"templ.Component", "templ.Handler"}}, + {Name: "Frequently Asked Questions", SubItems: []string{}}, + {Name: "Contributing and Support", SubItems: []string{}}, + {Name: "Best Practices", SubItems: []string{"Keeping templ components pure and avoiding bugs"}}, + {Name: "Conclusion", SubItems: []string{"Summary and next steps for learning more about templ"}}, + } + + var items []ItemToCreate + + for i, section := range sections { + i += 1 + current := ItemToCreate{ + Name: section.Name, + Path: fmt.Sprintf("%02d-%s", i+1, slug.Make(section.Name)), + IsFile: false, + } + items = append(items, current) + + // Add category.json + items = append(items, ItemToCreate{ + Path: fmt.Sprintf("%s/_category_.json", current.Path), + IsFile: true, + Content: categoryJSON(i+1, section.Name), + }) + + if len(section.SubItems) == 0 { + fileItem := ItemToCreate{ + Name: section.Name, + Path: fmt.Sprintf("%s/index.md", current.Path), + IsFile: true, + Content: fmt.Sprintf("# %s\n", section.Name), + } + items = append(items, fileItem) + } + for j, subItem := range section.SubItems { + fileItem := ItemToCreate{ + Name: subItem, + Path: fmt.Sprintf("%s/%02d-%s.md", current.Path, j+1, slug.Make(subItem)), + IsFile: true, + Content: fmt.Sprintf("# %s\n", subItem), + } + items = append(items, fileItem) + } + } + + for _, item := range items { + fmt.Println(item.Path) + if item.IsFile { + os.WriteFile(item.Path, []byte(item.Content), 0644) + continue + } + os.Mkdir(item.Path, 0755) + } +} + +func categoryJSON(position int, label string) string { + sw := new(strings.Builder) + enc := json.NewEncoder(sw) + enc.SetIndent("", " ") + err := enc.Encode(Category{ + Position: position, + Label: label, + }) + if err != nil { + panic("failed to create JSON: " + err.Error()) + } + return sw.String() +} + +type Category struct { + Position int `json:"position"` + Label string `json:"label"` +} diff --git a/templ/docs/docusaurus.config.js b/templ/docs/docusaurus.config.js new file mode 100644 index 0000000..bc8273b --- /dev/null +++ b/templ/docs/docusaurus.config.js @@ -0,0 +1,102 @@ +// @ts-check +// Note: type annotations allow type checking and IDEs autocompletion + +const lightCodeTheme = require('prism-react-renderer').themes.github; +const darkCodeTheme = require('prism-react-renderer').themes.dracula; + +/** @type {import('@docusaurus/types').Config} */ +const config = { + title: 'templ docs', + tagline: 'A language for writing HTML user interfaces in Go. ', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://templ.guide', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'a-h', // Usually your GitHub org/user name. + projectName: 'templ', // Usually your repo name. + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internalization, you can use this field to set useful + // metadata like html lang. For example, if your site is Chinese, you may want + // to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + markdown: { + mermaid: true, + }, + themes: ['@docusaurus/theme-mermaid'], + + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + sidebarPath: require.resolve('./sidebars.js'), + routeBasePath: '/', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/a-h/templ/tree/main/docs/', + }, + blog: false, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }), + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + // Replace with your project's social card + image: 'img/social-card.jpg', + navbar: { + logo: { + alt: 'Templ Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Docs', + }, + { + href: 'https://github.com/a-h/templ', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + copyright: `Copyright © ${new Date().getFullYear()} Adrian Hesketh, Built with Docusaurus.`, + }, + prism: { + theme: lightCodeTheme, + darkTheme: darkCodeTheme, + additionalLanguages: ['nix', 'bash', 'json'], + }, + algolia: { + appId: 'PVCVW9GL1Z', + apiKey: '0823e4b4272c719b5338ed75843f38ef', + indexName: 'templ', + }, + }), +}; + +module.exports = config; diff --git a/templ/docs/package-lock.json b/templ/docs/package-lock.json new file mode 100644 index 0000000..74e525c --- /dev/null +++ b/templ/docs/package-lock.json @@ -0,0 +1,19020 @@ +{ + "name": "docs", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "docs", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "^3.6.3", + "@docusaurus/preset-classic": "^3.6.3", + "@docusaurus/theme-mermaid": "^3.6.3", + "@mdx-js/react": "^3.0.1", + "clsx": "2.1.1", + "prism-react-renderer": "^2.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.6.3", + "@docusaurus/tsconfig": "^3.6.3", + "@types/react": "^18.3.3", + "prismjs": "^1.29.0", + "typescript": "~5.5.3" + }, + "engines": { + "node": ">=18.2" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/cache-browser-local-storage": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", + "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/cache-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", + "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==", + "license": "MIT" + }, + "node_modules/@algolia/cache-in-memory": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", + "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.18.0.tgz", + "integrity": "sha512-DLIrAukjsSrdMNNDx1ZTks72o4RH/1kOn8Wx5zZm8nnqFexG+JzY4SANnCNEjnFQPJTTvC+KpgiNW/CP2lumng==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-account": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", + "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-account/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", + "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-analytics/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.18.0.tgz", + "integrity": "sha512-X1WMSC+1ve2qlMsemyTF5bIjwipOT+m99Ng1Tyl36ZjQKTa54oajBKE0BrmM8LD8jGdtukAgkUhFoYOaRbMcmQ==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.18.0.tgz", + "integrity": "sha512-FAJRNANUOSs/FgYOJ/Njqp+YTe4TMz2GkeZtfsw1TMiA5mVNRS/nnMpxas9771aJz7KTEWvK9GwqPs0K6RMYWg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", + "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-personalization/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.18.0.tgz", + "integrity": "sha512-x6XKIQgKFTgK/bMasXhghoEjHhmgoP61pFPb9+TaUJ32aKOGc65b12usiGJ9A84yS73UDkXS452NjyP50Knh/g==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.18.0.tgz", + "integrity": "sha512-qI3LcFsVgtvpsBGR7aNSJYxhsR+Zl46+958ODzg8aCxIcdxiK7QEVLMJMZAR57jGqW0Lg/vrjtuLFDMfSE53qA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" + }, + "node_modules/@algolia/ingestion": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.18.0.tgz", + "integrity": "sha512-bGvJg7HnGGm+XWYMDruZXWgMDPVt4yCbBqq8DM6EoaMBK71SYC4WMfIdJaw+ABqttjBhe6aKNRkWf/bbvYOGyw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/logger-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", + "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==", + "license": "MIT" + }, + "node_modules/@algolia/logger-console": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", + "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", + "license": "MIT", + "dependencies": { + "@algolia/logger-common": "4.24.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.18.0.tgz", + "integrity": "sha512-lBssglINIeGIR+8KyzH05NAgAmn1BCrm5D2T6pMtr/8kbTHvvrm1Zvcltc5dKUQEFyyx3J5+MhNc7kfi8LdjVw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", + "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", + "license": "MIT", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/recommend/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.18.0.tgz", + "integrity": "sha512-1XFjW0C3pV0dS/9zXbV44cKI+QM4ZIz9cpatXpsjRlq6SUCpLID3DZHsXyE6sTb8IhyPaUjk78GEJT8/3hviqg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", + "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==", + "license": "MIT" + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.18.0.tgz", + "integrity": "sha512-0uodeNdAHz1YbzJh6C5xeQ4T6x5WGiUxUq3GOaT/R4njh5t78dq+Rb187elr7KtnjUmETVVuCvmEYaThfTHzNg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.18.0.tgz", + "integrity": "sha512-tZCqDrqJ2YE2I5ukCQrYN8oiF6u3JIdCxrtKq+eniuLkjkO78TKRnXrVcKZTmfFJyyDK8q47SfDcHzAA3nHi6w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/transporter": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", + "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", + "license": "MIT", + "dependencies": { + "@algolia/cache-common": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-0.4.1.tgz", + "integrity": "sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^0.2.0", + "tinyexec": "^0.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", + "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", + "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz", + "integrity": "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.3.tgz", + "integrity": "sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.26.3.tgz", + "integrity": "sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", + "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", + "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.4.tgz", + "integrity": "sha512-7DFHlPuIxviKYZrOiwVU/PiHLm3lLUR23OMuEEtfEOQTOp9hzQ2JjdY6X5H18RVuUPJqSCI+qNnD5iOLMVE0bA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.1.tgz", + "integrity": "sha512-XOfhI7GShVcKiKwmPAnWSqd2tBR0uxt+runAxttbSp/LY2U16yAVPmAf7e9q4JJ0d+xMNmpwNDLBXnmRCl3HMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.7.tgz", + "integrity": "sha512-aDHYmhNIHR6iLw4ElWhf+tRqqaXwKnMl0YsQ/X105Zc4dQwe6yJpMrTN6BwOoESrkDjOYMOfORviSSLeDTJkdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.7.tgz", + "integrity": "sha512-e68Nev4CxZYCLcrfWhHH4u/N1YocOfTmw67/kVX5Rb7rnguqqLyxPjhHWjSBX8o4bmyuukmNf3wrUSU3//kT7g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.4.tgz", + "integrity": "sha512-YItlZUOuZJCBlRaCf8Aucc1lgN41qYGALMly0qQllrxYJhiyzlI6RxOTMUvtWk+KhS8GphMDsDhKQ7KTPfEMSw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.6.tgz", + "integrity": "sha512-IgJA5DQsQLu/upA3HcdvC6xEMR051ufebBTIXZ5E9/9iiaA7juXWz1ceYj814lnDYP/7eWjZnw0grRJlX4eI6g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.7.tgz", + "integrity": "sha512-gzFEZPoOkY0HqGdyeBXR3JP218Owr683u7KOZazTK7tQZBE8s2yhg06W1tshOqk7R7SWvw9gkw2TQogKpIW8Xw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.7.tgz", + "integrity": "sha512-WgEyBeg6glUeTdS2XT7qeTFBthTJuXlS9GFro/DVomj7W7WMTamAwpoP4oQCq/0Ki2gvfRYFi/uZtmRE14/DFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.7.tgz", + "integrity": "sha512-LKYqjO+wGwDCfNIEllessCBWfR4MS/sS1WXO+j00KKyOjm7jDW2L6jzUmqASEiv/kkJO39GcoIOvTTfB3yeBUA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.0.tgz", + "integrity": "sha512-9QT5TDGgx7wD3EEMN3BSUG6ckb6Eh5gSPT5kZoVtUuAonfPmLDJyPhqR4ntPpMYhUKAMVKAg3I/AgzqHMSeLhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.0.tgz", + "integrity": "sha512-dv2lNUKR+JV+OOhZm9paWzYBXOCi+rJPqJ2cJuhh9xd8USVrd0cBEPczla81HNOyThMQWeCcdln3gZkQV2kYxA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.1.tgz", + "integrity": "sha512-JLp3POui4S1auhDR0n8wHd/zTOWmMsmK3nQd3hhL6FhWPaox5W7j1se6zXOG/aP07wV2ww0lxbKYGwbBszOtfQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.7.tgz", + "integrity": "sha512-ZZ0rwlanYKOHekyIPaU+sVm3BEHCe+Ha0/px+bmHe62n0Uc1lL34vbwrLYn6ote8PHlsqzKeTQdIejQCJ05tfw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.3.tgz", + "integrity": "sha512-OC1IlG/yoGJdi0Y+7duz/kU/beCwO+Gua01sD6GtOtLi7ByQUpcIqs7UE/xuRPay4cHgOMatWdnDdsIDjnWpPw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.6.tgz", + "integrity": "sha512-J1+4Fr2W3pLZsfxkFazK+9kr96LhEYqoeBszLmFjb6AjYs+g9oDAw3J5oQignLKk3rC9XHW+ebPTZ9FaW5u5pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.4.tgz", + "integrity": "sha512-AnGjVslHMm5xw9keusQYvjVWvuS7KWK+OJagaG0+m9QnIjZsrysD2kJP/tr/UJIyYtMCtu8OkUd+Rajb4DqtIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz", + "integrity": "sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.7.tgz", + "integrity": "sha512-I6WFQIbEKG2IO3vhaMGZDkucbCaUSXMxvHNzDdnfsTCF5tc0UlV3Oe2AhamatQoKFjBi75dSEMrgWq3+RegsOQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz", + "integrity": "sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-1.0.2.tgz", + "integrity": "sha512-vBCT6JvgdEkvRc91NFoNrLjgGtkLWt47GKT6E2UDn3nd8ZkMBiziQ1Md1OiKoSsgzxsSnGKG3RVdhlbdZEkHjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.7.tgz", + "integrity": "sha512-apbT31vsJVd18MabfPOnE977xgct5B1I+Jpf+Munw3n6kKb1MMuUmGGH+PT9Hm/fFs6fe61Q/EWnkrb4bNoNQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.1.tgz", + "integrity": "sha512-MslYkZCeMQDxetNkfmmQYgKCy4c+w9pPDfgOBCJOo/RI1RveEUdZQYtOfrC6cIZB7sD7/PHr2VGOcMXlZawrnA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.6.tgz", + "integrity": "sha512-/dwlO9w8vfKgiADxpxUbZOWlL5zKoRIsCymYoh1IPuBsXODKanKnfuZRr32DEqT0//3Av1VjfNZU9yhxtEfIeA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.1.tgz", + "integrity": "sha512-xPZIikbx6jyzWvhms27uugIc0I4ykH4keRvoa3rxX5K7lEhkbd54rjj/dv60qOCTisoS+3bmwJTeyV1VNBrXaw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.6.tgz", + "integrity": "sha512-c4Y1D2Why/PeccaSouXnTt6WcNHJkoJRidV2VW9s5gJ97cNxnLgQ4Qj8qOqkIR9VmTQKJyNcbF4hy79ZQnWD7A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-analytics": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.18.0.tgz", + "integrity": "sha512-0VpGG2uQW+h2aejxbG8VbnMCQ9ary9/ot7OASXi6OjE0SRkYQ/+pkW+q09+IScif3pmsVVYggmlMPtAsmYWHng==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/client-personalization": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.18.0.tgz", + "integrity": "sha512-I2dc94Oiwic3SEbrRp8kvTZtYpJjGtg5y5XnqubgnA15AgX59YIY8frKsFG8SOH1n2rIhUClcuDkxYQNXJLg+w==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/recommend": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.18.0.tgz", + "integrity": "sha512-uSnkm0cdAuFwdMp4pGT5vHVQ84T6AYpTZ3I0b3k/M3wg4zXDhl3aCiY8NzokEyRLezz/kHLEEcgb/tTTobOYVw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docsearch/react/node_modules/algoliasearch": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.18.0.tgz", + "integrity": "sha512-/tfpK2A4FpS0o+S78o3YSdlqXr0MavJIDlFK3XZrlXLy7vaRXJvW5jYg3v5e/wCaF8y0IpMjkYLhoV6QqfpOgw==", + "license": "MIT", + "dependencies": { + "@algolia/client-abtesting": "5.18.0", + "@algolia/client-analytics": "5.18.0", + "@algolia/client-common": "5.18.0", + "@algolia/client-insights": "5.18.0", + "@algolia/client-personalization": "5.18.0", + "@algolia/client-query-suggestions": "5.18.0", + "@algolia/client-search": "5.18.0", + "@algolia/ingestion": "1.18.0", + "@algolia/monitoring": "1.18.0", + "@algolia/recommend": "5.18.0", + "@algolia/requester-browser-xhr": "5.18.0", + "@algolia/requester-fetch": "5.18.0", + "@algolia/requester-node-http": "5.18.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.6.3.tgz", + "integrity": "sha512-7dW9Hat9EHYCVicFXYA4hjxBY38+hPuCURL8oRF9fySRm7vzNWuEOghA1TXcykuXZp0HLG2td4RhDxCvGG7tNw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/runtime-corejs3": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.6.3.tgz", + "integrity": "sha512-47JLuc8D4wA+6VOvmMd5fUC9rFppBQpQOnxDYiVXffm/DeV/wmm3sbpNd5Y+O+G2+nevLTRnvCm/qyancv0Y3A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.6.3", + "@docusaurus/cssnano-preset": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.2", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.8.1", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.1", + "null-loader": "^4.0.1", + "postcss": "^8.4.26", + "postcss-loader": "^7.3.3", + "postcss-preset-env": "^10.1.0", + "react-dev-utils": "^12.0.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^6.0.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.6.3.tgz", + "integrity": "sha512-xL7FRY9Jr5DWqB6pEnqgKqcMPJOX5V0pgWXi5lCiih11sUBmcFKM7c3+GyxcVeeWFxyYSDP3grLTWqJoP4P9Vw==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.6.3", + "@docusaurus/bundler": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "del": "^6.1.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-dev-utils": "^12.0.1", + "react-helmet-async": "^1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "rtl-detect": "^1.0.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.6", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^4.15.2", + "webpack-merge": "^6.0.1" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.3.tgz", + "integrity": "sha512-qP7SXrwZ+23GFJdPN4aIHQrZW+oH/7tzwEuc/RNL0+BdZdmIjYQqUxdXsjE4lFxLNZjj0eUrSNYIS6xwfij+5Q==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.4.38", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.6.3.tgz", + "integrity": "sha512-xSubJixcNyMV9wMV4q0s47CBz3Rlc5jbcCCuij8pfQP8qn/DIpt0ks8W6hQWzHAedg/J/EwxxUOUrnEoKzJo8g==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.6.3.tgz", + "integrity": "sha512-3iJdiDz9540ppBseeI93tWTDtUGVkxzh59nMq4ignylxMuXBLK8dFqVeaEor23v1vx6TrGKZ2FuLaTB+U7C0QQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^1.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.3.tgz", + "integrity": "sha512-MjaXX9PN/k5ugNvfRZdWyKWq4FsrhN4LEXaj0pEmMebJuBNlFeGyKQUa9DRhJHpadNaiMLrbo9m3U7Ig5YlsZg==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.6.3", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "*", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.3.tgz", + "integrity": "sha512-k0ogWwwJU3pFRFfvW1kRVHxzf2DutLGaaLjAnHVEU6ju+aRP0Z5ap/13DHyPOfHeE4WKpn/M0TqjdwZAcY3kAw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "cheerio": "1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "reading-time": "^1.5.0", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.3.tgz", + "integrity": "sha512-r2wS8y/fsaDcxkm20W5bbYJFPzdWdEaTWVYjNxlHlcmX086eqQR1Fomlg9BHTJ0dLXPzAlbC8EN4XqMr3QzNCQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.3.tgz", + "integrity": "sha512-eHrmTgjgLZsuqfsYr5X2xEwyIcck0wseSofWrjTwT9FLOWp+KDmMAuVK+wRo7sFImWXZk3oV/xX/g9aZrhD7OA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.6.3.tgz", + "integrity": "sha512-zB9GXfIZNPRfzKnNjU6xGVrqn9bPXuGhpjgsuc/YtcTDjnjhasg38NdYd5LEqXex5G/zIorQgWB3n6x/Ut62vQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^1.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.3.tgz", + "integrity": "sha512-rCDNy1QW8Dag7nZq67pcum0bpFLrwvxJhYuVprhFh8BMBDxV0bY+bAkGHbSf68P3Bk9C3hNOAXX1srGLIDvcTA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.3.tgz", + "integrity": "sha512-+OyDvhM6rqVkQOmLVkQWVJAizEEfkPzVWtIHXlWPOCFGK9X4/AWeBSrU0WG4iMg9Z4zD4YDRrU+lvI4s6DSC+w==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.3.tgz", + "integrity": "sha512-1M6UPB13gWUtN2UHX083/beTn85PlRI9ABItTl/JL1FJ5dJTWWFXXsHf9WW/6hrVwthwTeV/AGbGKvLKV+IlCA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.3.tgz", + "integrity": "sha512-94qOO4M9Fwv9KfVQJsgbe91k+fPJ4byf1L3Ez8TUa6TAFPo/BrLwQ80zclHkENlL1824TuxkcMKv33u6eydQCg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.6.3.tgz", + "integrity": "sha512-VHSYWROT3flvNNI1SrnMOtW1EsjeHNK9dhU6s9eY5hryZe79lUqnZJyze/ymDe2LXAqzyj6y5oYvyBoZZk6ErA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/plugin-content-blog": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/plugin-content-pages": "3.6.3", + "@docusaurus/plugin-debug": "3.6.3", + "@docusaurus/plugin-google-analytics": "3.6.3", + "@docusaurus/plugin-google-gtag": "3.6.3", + "@docusaurus/plugin-google-tag-manager": "3.6.3", + "@docusaurus/plugin-sitemap": "3.6.3", + "@docusaurus/theme-classic": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-search-algolia": "3.6.3", + "@docusaurus/types": "3.6.3" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.6.3.tgz", + "integrity": "sha512-1RRLK1tSArI2c00qugWYO3jRocjOZwGF1mBzPPylDVRwWCS/rnWWR91ChdbbaxIupRJ+hX8ZBYrwr5bbU0oztQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/plugin-content-blog": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/plugin-content-pages": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-translations": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.4.26", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.6.3.tgz", + "integrity": "sha512-b8ZkhczXHDxWWyvz+YJy4t/PlPbEogTTbgnHoflYnH7rmRtyoodTsu8WVM12la5LmlMJBclBXFl29OH8kPE7gg==", + "license": "MIT", + "dependencies": { + "@docusaurus/mdx-loader": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-mermaid": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-3.6.3.tgz", + "integrity": "sha512-kIqpjNCP/9R2GGf8UmiDxD3CkOAEJuJIEFlaKMgQtjVxa/vH+9PLI1+DFbArGoG4+0ENTYUq8phHPW7SeL36uQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.6.3", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "mermaid": ">=10.4", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.3.tgz", + "integrity": "sha512-rt+MGCCpYgPyWCGXtbxlwFbTSobu15jWBTPI2LHsHNa5B0zSmOISX6FWYAPt5X1rNDOqMGM0FATnh7TBHRohVA==", + "license": "MIT", + "dependencies": { + "@docsearch/react": "^3.5.2", + "@docusaurus/core": "3.6.3", + "@docusaurus/logger": "3.6.3", + "@docusaurus/plugin-content-docs": "3.6.3", + "@docusaurus/theme-common": "3.6.3", + "@docusaurus/theme-translations": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-validation": "3.6.3", + "algoliasearch": "^4.18.0", + "algoliasearch-helper": "^3.13.3", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.6.3.tgz", + "integrity": "sha512-Gb0regclToVlngSIIwUCtBMQBq48qVUaN1XQNKW4XwlsgUyk0vP01LULdqbem7czSwIeBAFXFoORJ0RPX7ht/w==", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/tsconfig": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/tsconfig/-/tsconfig-3.6.3.tgz", + "integrity": "sha512-1pT/rTrRpMV15E4tJH95W5PrjboMn5JkKF+Ys8cTjMegetiXjs0gPFOSDA5hdTlberKQLDO50xPjMJHondLuzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docusaurus/types": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.6.3.tgz", + "integrity": "sha512-xD9oTGDrouWzefkhe9ogB2fDV96/82cRpNGx2HIvI5L87JHNhQVIWimQ/3JIiiX/TEd5S9s+VO6FFguwKNRVow==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "^1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.6.3.tgz", + "integrity": "sha512-0R/FR3bKVl4yl8QwbL4TYFfR+OXBRpVUaTJdENapBGR3YMwfM6/JnhGilWQO8AOwPJGtGoDK7ib8+8UF9f3OZQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/types": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "@svgr/webpack": "^8.1.0", + "escape-string-regexp": "^4.0.0", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "shelljs": "^0.8.5", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.6.3.tgz", + "integrity": "sha512-v4nKDaANLgT3pMBewHYEMAl/ufY0LkXao1QkFWzI5huWFOmNQ2UFzv2BiKeHX5Ownis0/w6cAyoxPhVdDonlSQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.6.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.6.3.tgz", + "integrity": "sha512-bhEGGiN5BE38h21vjqD70Gxg++j+PfYVddDUE5UFvLDup68QOcpD33CLr+2knPorlxRbEaNfz6HQDUMQ3HuqKw==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.6.3", + "@docusaurus/utils": "3.6.3", + "@docusaurus/utils-common": "3.6.3", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-2.2.1.tgz", + "integrity": "sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^0.4.1", + "@antfu/utils": "^0.7.10", + "@iconify/types": "^2.0.0", + "debug": "^4.4.0", + "globals": "^15.13.0", + "kolorist": "^1.8.0", + "local-pkg": "^0.5.1", + "mlly": "^1.7.3" + } + }, + "node_modules/@iconify/utils/node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz", + "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", + "integrity": "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA==", + "license": "MIT", + "dependencies": { + "langium": "3.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.25", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", + "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz", + "integrity": "sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.15", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", + "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==", + "license": "MIT" + }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "22.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", + "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prismjs": { + "version": "1.26.4", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz", + "integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + }, + "node_modules/@types/qs": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" + }, + "node_modules/@types/react": { + "version": "18.3.4", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", + "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", + "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", + "license": "MIT", + "dependencies": { + "@algolia/cache-browser-local-storage": "4.24.0", + "@algolia/cache-common": "4.24.0", + "@algolia/cache-in-memory": "4.24.0", + "@algolia/client-account": "4.24.0", + "@algolia/client-analytics": "4.24.0", + "@algolia/client-common": "4.24.0", + "@algolia/client-personalization": "4.24.0", + "@algolia/client-search": "4.24.0", + "@algolia/logger-common": "4.24.0", + "@algolia/logger-console": "4.24.0", + "@algolia/recommend": "4.24.0", + "@algolia/requester-browser-xhr": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/requester-node-http": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.22.6", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.22.6.tgz", + "integrity": "sha512-F2gSb43QHyvZmvH/2hxIjbk/uFdO2MguQYTFP7J+RowMW1csjIODMobEnpLI8nbLQuzZnGZdIxl5Bpy1k9+CFQ==", + "license": "MIT", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-common": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", + "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/client-search": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", + "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "4.24.0", + "@algolia/requester-common": "4.24.0", + "@algolia/transporter": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-browser-xhr": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", + "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/algoliasearch/node_modules/@algolia/requester-node-http": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", + "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "license": "MIT", + "dependencies": { + "@algolia/requester-common": "4.24.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", + "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.3", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.3" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.53.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz", + "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.3.3.tgz", + "integrity": "sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz", + "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.2.tgz", + "integrity": "sha512-nzol/h+E0bId46Kn2dQH5VElaknX2Sr0hFuB/1EomdC7j+OISt2ZzK7EHX9DZDY53WbIVAR7FYKSO2XnSf07MQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.2.3.tgz", + "integrity": "sha512-9BDG5XmJrJQQnJ51VFxXCAtpZ5ebDlAREmO8sxMOVU0aSxN/gocbctjIG5LMh3WBUq+xTlb/jw2LoljBEqraTA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/cytoscape": { + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz", + "integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz", + "integrity": "sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dompurify": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.3.tgz", + "integrity": "sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/domutils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.1.tgz", + "integrity": "sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==" + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.2.1.tgz", + "integrity": "sha512-Vt2UOjyPbNQQgT5eJh+K5aATti0OjCIAGc9SgMdOFYbohuifsWclR74l0iZTJwePMgWYdX1hlVS+dedH9XV8kw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "function-bind": "^1.1.2", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", + "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz", + "integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree/node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, + "node_modules/hast-util-to-estree/node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", + "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", + "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz", + "integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.45", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", + "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/katex": { + "version": "0.16.11", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz", + "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/langium": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.0.0.tgz", + "integrity": "sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", + "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", + "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz", + "integrity": "sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mermaid": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.4.1.tgz", + "integrity": "sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.0.1", + "@iconify/utils": "^2.1.32", + "@mermaid-js/parser": "^0.3.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.2", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.11", + "dayjs": "^1.11.10", + "dompurify": "^3.2.1", + "katex": "^0.16.9", + "khroma": "^2.1.0", + "lodash-es": "^4.17.21", + "marked": "^13.0.2", + "roughjs": "^4.6.6", + "stylis": "^4.3.1", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.1" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", + "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", + "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.3.tgz", + "integrity": "sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mlly": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.3.tgz", + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^1.1.2", + "pkg-types": "^1.2.1", + "ufo": "^1.5.4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/null-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/null-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-manager-detector": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.8.tgz", + "integrity": "sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA==", + "license": "MIT" + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-types": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.0.tgz", + "integrity": "sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.3", + "pathe": "^1.1.2" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.7.tgz", + "integrity": "sha512-EZvAHsvyASX63vXnyXOIynkxhaHRSsdb7z6yiXKIovGXAolW4cMZ3qoh7k3VdTsLBS6VGdksGfIo3r6+waLoOw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.5.tgz", + "integrity": "sha512-SQHhayVNgDvSAdX9NQ/ygcDQGEY+aSF4b/96z7QUX6mqL5yl/JgG/DywcF6fW9XbnCRE+aVYk+9/nqGuzOPWeQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.4.tgz", + "integrity": "sha512-QnW8FCCK6q+4ierwjnmXF9Y9KF8q0JkbgVfvQEMa93x1GT8FvOiUevWCN2YLaOWyByeDX8S6VFbZEeWoAoXs2A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.4.tgz", + "integrity": "sha512-ASOXqNvDCE0dAJ/5qixxPeL1aOVGHGW2JwSy7HyjWNbnWTQCl+fDc968HY1jCmZI0+BaYT5CxsOiUhavpG/7eg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.4", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.0.tgz", + "integrity": "sha512-JkIGah3RVbdSEIrcobqj4Gzq0h53GG4uqDPsho88SgY84WnpkTpI0k50MFK/sX7XqVisZ6OqUfFnoUO6m1WWdg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.7.tgz", + "integrity": "sha512-+ONj2bpOQfsCKZE2T9VGMyVVdGcGUpr7u3SVfvkJlvhTRmDCfY25k4Jc8fubB9DclAPR4+w8uVtDZmdRgdAHig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.0.0.tgz", + "integrity": "sha512-HpIdsdieClTjXLOyYdUPAX/XQASNIwdKt5hoZW08ZOAiI+tbV0ta1oclkpVkW5ANU+xJvk3KkA0FejkjGLXUkg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.1.tgz", + "integrity": "sha512-VbqqHkOBOt4Uu3G8Dm8n6lU5+9cJFxiuty9+4rcoyRPO9zZS1JIs6td49VIoix3qYqELHlJIn46Oih9SAKo+yQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-resolve-nested": "^3.0.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.0.0.tgz", + "integrity": "sha512-ZoK24Yku6VJU1gS79a5PFmC8yn3wIapiKmPgun0hZgEI5AOqgH2kiPRsPz1qkGv4HL+wuDLH83yQyk6inMYrJQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.1.3.tgz", + "integrity": "sha512-9qzVhcMFU/MnwYHyYpJz4JhGku/4+xEiPTmhn0hj3IxnUYlEF9vbh7OC1KoLAnenS6Fgg43TKNp9xcuMeAi4Zw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-cascade-layers": "^5.0.1", + "@csstools/postcss-color-function": "^4.0.7", + "@csstools/postcss-color-mix-function": "^3.0.7", + "@csstools/postcss-content-alt-text": "^2.0.4", + "@csstools/postcss-exponential-functions": "^2.0.6", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.7", + "@csstools/postcss-gradients-interpolation-method": "^5.0.7", + "@csstools/postcss-hwb-function": "^4.0.7", + "@csstools/postcss-ic-unit": "^4.0.0", + "@csstools/postcss-initial": "^2.0.0", + "@csstools/postcss-is-pseudo-class": "^5.0.1", + "@csstools/postcss-light-dark-function": "^2.0.7", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.3", + "@csstools/postcss-media-minmax": "^2.0.6", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.4", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.0", + "@csstools/postcss-oklab-function": "^4.0.7", + "@csstools/postcss-progressive-custom-properties": "^4.0.0", + "@csstools/postcss-random-function": "^1.0.2", + "@csstools/postcss-relative-color-syntax": "^3.0.7", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.1", + "@csstools/postcss-stepped-value-functions": "^4.0.6", + "@csstools/postcss-text-decoration-shorthand": "^4.0.1", + "@csstools/postcss-trigonometric-functions": "^4.0.6", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.2", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.2.3", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.7", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.5", + "postcss-custom-properties": "^14.0.4", + "postcss-custom-selectors": "^8.0.4", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.0", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.7", + "postcss-logical": "^8.0.0", + "postcss-nesting": "^13.0.1", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "license": "MIT", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", + "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, + "node_modules/react-helmet-async": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-json-view-lite": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-1.5.0.tgz", + "integrity": "sha512-nWqA1E4jKPklL2jvHWs6s+7Na0qNgw9HCP6xehdQJeg6nPBTFZgGwyko9Q0oj+jQWKTTVRS30u0toM5wiuL3iw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", + "license": "MIT" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz", + "integrity": "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.0.tgz", + "integrity": "sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rtl-detect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.1.2.tgz", + "integrity": "sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==" + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/sitemap": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.2.tgz", + "integrity": "sha512-ARCqzHJ0p4gWt+j7NlU5eDlIO9+Rkr/JhPFZKKQ1l5GCus7rJH4UdrlVAh0xC/gDS/Qir2UMxqYNHtsKr2rpCw==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "license": "MIT", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "license": "MIT" + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpackbar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", + "integrity": "sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "consola": "^3.2.3", + "figures": "^3.2.0", + "markdown-table": "^2.0.0", + "pretty-time": "^1.1.0", + "std-env": "^3.7.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/webpackbar/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/webpackbar/node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpackbar/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpackbar/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/templ/docs/package.json b/templ/docs/package.json new file mode 100644 index 0000000..06de284 --- /dev/null +++ b/templ/docs/package.json @@ -0,0 +1,49 @@ +{ + "name": "docs", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "npm run generate-llms-md && docusaurus start", + "build": "npm run generate-llms-md && docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "generate-llms-md": "find docs | grep '.*md$' | xargs cat > ./static/llms.md" + }, + "dependencies": { + "@docusaurus/core": "^3.6.3", + "@docusaurus/preset-classic": "^3.6.3", + "@docusaurus/theme-mermaid": "^3.6.3", + "@mdx-js/react": "^3.0.1", + "clsx": "2.1.1", + "prism-react-renderer": "^2.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.6.3", + "@docusaurus/tsconfig": "^3.6.3", + "@types/react": "^18.3.3", + "prismjs": "^1.29.0", + "typescript": "~5.5.3" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "engines": { + "node": ">=18.2" + } +} diff --git a/templ/docs/sidebars.js b/templ/docs/sidebars.js new file mode 100644 index 0000000..9ab54c2 --- /dev/null +++ b/templ/docs/sidebars.js @@ -0,0 +1,33 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + 'intro', + 'hello', + { + type: 'category', + label: 'Tutorial', + items: ['tutorial-basics/create-a-document'], + }, + ], + */ +}; + +module.exports = sidebars; diff --git a/templ/docs/src/css/custom.css b/templ/docs/src/css/custom.css new file mode 100644 index 0000000..2ef9109 --- /dev/null +++ b/templ/docs/src/css/custom.css @@ -0,0 +1,34 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #008391; + --ifm-color-primary-dark: #007380; + --ifm-color-primary-darker: #006570; + --ifm-color-primary-darkest: #005761; + --ifm-color-primary-light: #0093A3; + --ifm-color-primary-lighter: #00A5B8; + --ifm-color-primary-lightest: #00B3C7; + --ifm-code-font-size: 95%; + --ifm-footer-background-color: #003238; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +.footer--dark { + --ifm-footer-background-color: #173E42; +} +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #DBBC30; + --ifm-color-primary-dark: #D0B125; + --ifm-color-primary-darker: #BA9E21; + --ifm-color-primary-darkest: #A0881C; + --ifm-color-primary-light: #E7C946; + --ifm-color-primary-lighter: #F1D65F; + --ifm-color-primary-lightest: #F7E078; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/templ/docs/src/theme/prism-include-languages.js b/templ/docs/src/theme/prism-include-languages.js new file mode 100644 index 0000000..4f48314 --- /dev/null +++ b/templ/docs/src/theme/prism-include-languages.js @@ -0,0 +1,171 @@ +import siteConfig from '@generated/docusaurus.config'; +export default function prismIncludeLanguages(PrismObject) { + const { + themeConfig: { + prism + }, + } = siteConfig; + const { + additionalLanguages + } = prism; + // Prism components work on the Prism instance on the window, while prism- + // react-renderer uses its own Prism instance. We temporarily mount the + // instance onto window, import components to enhance it, then remove it to + // avoid polluting global namespace. + // You can mutate PrismObject: registering plugins, deleting languages... As + // long as you don't re-assign it + globalThis.Prism = PrismObject; + additionalLanguages.forEach((lang) => { + // eslint-disable-next-line global-require, import/no-dynamic-require + require(`prismjs/components/prism-${lang}`); + }); + var go = globalThis.Prism.languages.extend('go', { + 'keyword': /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var|templ|css|script)\b/, + }); + + var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source; + var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source; + var spread = /(?:\{*\.{3}(?:(?!\{)[^{}]|)*\})/.source; + + /** + * @param {string} source + * @param {string} [flags] + */ + function re(source, flags) { + source = source + .replace(//g, function() { + return space; + }) + .replace(//g, function() { + return braces; + }) + .replace(//g, function() { + return spread; + }); + return RegExp(source, flags); + } + + spread = re(spread).source; + + + globalThis.Prism.languages.templ = globalThis.Prism.languages.extend('markup', go); + globalThis.Prism.languages.templ.tag.pattern = re( + /<\/?(?:[\w.:-]+(?:+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|))?|))**\/?)?>/.source + ); + + globalThis.Prism.languages.templ.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/; + globalThis.Prism.languages.templ.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/; + globalThis.Prism.languages.templ.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/; + globalThis.Prism.languages.templ.tag.inside['comment'] = go['comment']; + + globalThis.Prism.languages.insertBefore('inside', 'attr-name', { + 'spread': { + pattern: re(//.source), + inside: globalThis.Prism.languages.templ + } + }, globalThis.Prism.languages.templ.tag); + + globalThis.Prism.languages.insertBefore('inside', 'special-attr', { + 'script': { + // Allow for two levels of nesting + pattern: re(/=/.source), + alias: 'language-go', + inside: { + 'script-punctuation': { + pattern: /^=(?=\{)/, + alias: 'punctuation' + }, + rest: globalThis.Prism.languages.templ + }, + } + }, globalThis.Prism.languages.templ.tag); + + // The following will handle plain text inside tags + var stringifyToken = function(token) { + if (!token) { + return ''; + } + if (typeof token === 'string') { + return token; + } + if (typeof token.content === 'string') { + return token.content; + } + return token.content.map(stringifyToken).join(''); + }; + + var walkTokens = function(tokens) { + var openedTags = []; + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + var notTagNorBrace = false; + + if (typeof token !== 'string') { + if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') { + // We found a tag, now find its kind + + if (token.content[0].content[0].content === ' 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) { + // Pop matching opening tag + openedTags.pop(); + } + } else { + if (token.content[token.content.length - 1].content === '/>') { + // Autoclosed tag, ignore + } else { + // Opening tag + openedTags.push({ + tagName: stringifyToken(token.content[0].content[1]), + openedBraces: 0 + }); + } + } + } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') { + + // Here we might have entered a templ context inside a tag + openedTags[openedTags.length - 1].openedBraces++; + + } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') { + + // Here we might have left a templ context inside a tag + openedTags[openedTags.length - 1].openedBraces--; + + } else { + notTagNorBrace = true; + } + } + if (notTagNorBrace || typeof token === 'string') { + if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) { + // Here we are inside a tag, and not inside a templ context. + // That's plain text: drop any tokens matched. + var plainText = stringifyToken(token); + + // And merge text with adjacent text + if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) { + plainText += stringifyToken(tokens[i + 1]); + tokens.splice(i + 1, 1); + } + if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) { + plainText = stringifyToken(tokens[i - 1]) + plainText; + tokens.splice(i - 1, 1); + i--; + } + + tokens[i] = new globalThis.Prism.Token('plain-text', plainText, null, plainText); + } + } + + if (token.content && typeof token.content !== 'string') { + walkTokens(token.content); + } + } + }; + + globalThis.Prism.hooks.add('after-tokenize', function(env) { + if (env.language !== 'templ') { + return; + } + walkTokens(env.tokens); + }); +} diff --git a/templ/docs/static/.nojekyll b/templ/docs/static/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/templ/docs/static/img/docusaurus.png b/templ/docs/static/img/docusaurus.png new file mode 100644 index 0000000..f458149 Binary files /dev/null and b/templ/docs/static/img/docusaurus.png differ diff --git a/templ/docs/static/img/favicon.ico b/templ/docs/static/img/favicon.ico new file mode 100644 index 0000000..8490f74 Binary files /dev/null and b/templ/docs/static/img/favicon.ico differ diff --git a/templ/docs/static/img/logo.svg b/templ/docs/static/img/logo.svg new file mode 100644 index 0000000..a15d445 --- /dev/null +++ b/templ/docs/static/img/logo.svg @@ -0,0 +1,86 @@ + + + + + + + + + + </> TEMPL + + diff --git a/templ/docs/static/img/shadowdom.webm b/templ/docs/static/img/shadowdom.webm new file mode 100644 index 0000000..20167d8 Binary files /dev/null and b/templ/docs/static/img/shadowdom.webm differ diff --git a/templ/docs/static/img/social-card.jpg b/templ/docs/static/img/social-card.jpg new file mode 100644 index 0000000..94dcbdc Binary files /dev/null and b/templ/docs/static/img/social-card.jpg differ diff --git a/templ/docs/static/img/undraw_docusaurus_mountain.svg b/templ/docs/static/img/undraw_docusaurus_mountain.svg new file mode 100644 index 0000000..af961c4 --- /dev/null +++ b/templ/docs/static/img/undraw_docusaurus_mountain.svg @@ -0,0 +1,171 @@ + + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templ/docs/static/img/undraw_docusaurus_react.svg b/templ/docs/static/img/undraw_docusaurus_react.svg new file mode 100644 index 0000000..94b5cf0 --- /dev/null +++ b/templ/docs/static/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templ/docs/static/img/undraw_docusaurus_tree.svg b/templ/docs/static/img/undraw_docusaurus_tree.svg new file mode 100644 index 0000000..d9161d3 --- /dev/null +++ b/templ/docs/static/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templ/examples/blog/main.go b/templ/examples/blog/main.go new file mode 100644 index 0000000..caa5e03 --- /dev/null +++ b/templ/examples/blog/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "log" + "net/http" + + "github.com/a-h/templ" +) + +func main() { + // Use a template that doesn't take parameters. + http.Handle("/", templ.Handler(home())) + + // Use a template that accesses data or handles form posts. + http.Handle("/posts", NewPostsHandler()) + + // Start the server. + fmt.Println("listening on http://localhost:8000") + if err := http.ListenAndServe("localhost:8000", nil); err != nil { + log.Printf("error listening: %v", err) + } +} + +func NewPostsHandler() PostsHandler { + // Replace this in-memory function with a call to a database. + postsGetter := func() (posts []Post, err error) { + return []Post{{Name: "templ", Author: "author"}}, nil + } + return PostsHandler{ + GetPosts: postsGetter, + Log: log.Default(), + } +} + +type PostsHandler struct { + Log *log.Logger + GetPosts func() ([]Post, error) +} + +func (ph PostsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ps, err := ph.GetPosts() + if err != nil { + ph.Log.Printf("failed to get posts: %v", err) + http.Error(w, "failed to retrieve posts", http.StatusInternalServerError) + return + } + templ.Handler(posts(ps)).ServeHTTP(w, r) +} + +type Post struct { + Name string + Author string +} diff --git a/templ/examples/blog/posts.templ b/templ/examples/blog/posts.templ new file mode 100644 index 0000000..e284a3a --- /dev/null +++ b/templ/examples/blog/posts.templ @@ -0,0 +1,64 @@ +package main + +import ( + "fmt" + "time" +) + +templ headerTemplate(name string) { +
+

{ name }

+
+} + +templ footerTemplate() { +
+
© { fmt.Sprintf("%d", time.Now().Year()) }
+
+} + +templ navTemplate() { + +} + +templ layout(name string) { + + { name } + + @headerTemplate(name) + @navTemplate() +
+ { children... } +
+ + @footerTemplate() + +} + +templ postsTemplate(posts []Post) { +
+ for _, p := range posts { +
+
{ p.Name }
+
{ p.Author }
+
+ } +
+} + +templ home() { + @layout("Home") { +
Welcome to my website.
+ } +} + +templ posts(posts []Post) { + @layout("Posts") { + @postsTemplate(posts) + } +} diff --git a/templ/examples/blog/posts_templ.go b/templ/examples/blog/posts_templ.go new file mode 100644 index 0000000..b5a3d77 --- /dev/null +++ b/templ/examples/blog/posts_templ.go @@ -0,0 +1,358 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "fmt" + "time" +) + +func headerTemplate(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/blog/posts.templ`, Line: 10, Col: 12} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func footerTemplate() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
© ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", time.Now().Year())) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/blog/posts.templ`, Line: 16, Col: 52} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func navTemplate() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func layout(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/blog/posts.templ`, Line: 31, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerTemplate(name).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = navTemplate().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var6.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = footerTemplate().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func postsTemplate(posts []Post) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, p := range posts { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(p.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/blog/posts.templ`, Line: 47, Col: 53} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(p.Author) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/blog/posts.templ`, Line: 48, Col: 57} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func home() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var11 := templ.GetChildren(ctx) + if templ_7745c5c3_Var11 == nil { + templ_7745c5c3_Var11 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var12 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
Welcome to my website.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = layout("Home").Render(templ.WithChildren(ctx, templ_7745c5c3_Var12), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func posts(posts []Post) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var14 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = postsTemplate(posts).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = layout("Posts").Render(templ.WithChildren(ctx, templ_7745c5c3_Var14), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/blog/posts_test.go b/templ/examples/blog/posts_test.go new file mode 100644 index 0000000..2670482 --- /dev/null +++ b/templ/examples/blog/posts_test.go @@ -0,0 +1,210 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io" + "log" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/PuerkitoBio/goquery" +) + +func TestHeader(t *testing.T) { + // Pipe the rendered template into goquery. + r, w := io.Pipe() + go func() { + _ = headerTemplate("Posts").Render(context.Background(), w) + _ = w.Close() + }() + doc, err := goquery.NewDocumentFromReader(r) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + // Expect the component to include a testid. + if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 { + t.Error("expected data-testid attribute to be rendered, but it wasn't") + } + // Expect the page name to be set correctly. + expectedPageName := "Posts" + if actualPageName := doc.Find("h1").Text(); actualPageName != expectedPageName { + t.Errorf("expected page name %q, got %q", expectedPageName, actualPageName) + } +} + +func TestFooter(t *testing.T) { + // Pipe the rendered template into goquery. + r, w := io.Pipe() + go func() { + _ = footerTemplate().Render(context.Background(), w) + _ = w.Close() + }() + doc, err := goquery.NewDocumentFromReader(r) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + // Expect the component to include a testid. + if doc.Find(`[data-testid="footerTemplate"]`).Length() == 0 { + t.Error("expected data-testid attribute to be rendered, but it wasn't") + } + // Expect the copyright notice to include the current year. + expectedCopyrightNotice := fmt.Sprintf("© %d", time.Now().Year()) + if actualCopyrightNotice := doc.Find("div").Text(); actualCopyrightNotice != expectedCopyrightNotice { + t.Errorf("expected copyright notice %q, got %q", expectedCopyrightNotice, actualCopyrightNotice) + } +} + +func TestNav(t *testing.T) { + r, w := io.Pipe() + go func() { + _ = navTemplate().Render(context.Background(), w) + _ = w.Close() + }() + doc, err := goquery.NewDocumentFromReader(r) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + // Expect the component to include a testid. + if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 { + t.Error("expected data-testid attribute to be rendered, but it wasn't") + } +} + +func TestHome(t *testing.T) { + r, w := io.Pipe() + go func() { + _ = home().Render(context.Background(), w) + _ = w.Close() + }() + doc, err := goquery.NewDocumentFromReader(r) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + // Expect the page title to be set correctly. + expectedTitle := "Home" + if actualTitle := doc.Find("title").Text(); actualTitle != expectedTitle { + t.Errorf("expected title name %q, got %q", expectedTitle, actualTitle) + } + // Expect the header to be rendered. + if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 { + t.Error("expected data-testid attribute to be rendered, but it wasn't") + } + // Expect the navigation to be rendered. + if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 { + t.Error("expected nav to be rendered, but it wasn't") + } + // Expect the home template be rendered. + if doc.Find(`[data-testid="homeTemplate"]`).Length() == 0 { + t.Error("expected homeTemplate to be rendered, but it wasn't") + } +} + +func TestPosts(t *testing.T) { + testPosts := []Post{ + {Name: "Name1", Author: "Author1"}, + {Name: "Name2", Author: "Author2"}, + } + r, w := io.Pipe() + go func() { + _ = posts(testPosts).Render(context.Background(), w) + _ = w.Close() + }() + doc, err := goquery.NewDocumentFromReader(r) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + // Assert. + // Expect the page title to be set correctly. + expectedTitle := "Posts" + if actualTitle := doc.Find("title").Text(); actualTitle != expectedTitle { + t.Errorf("expected title name %q, got %q", expectedTitle, actualTitle) + } + // Expect the header to be rendered. + if doc.Find(`[data-testid="headerTemplate"]`).Length() == 0 { + t.Error("expected data-testid attribute to be rendered, but it wasn't") + } + // Expect the navigation to be rendered. + if doc.Find(`[data-testid="navTemplate"]`).Length() == 0 { + t.Error("expected nav to be rendered, but it wasn't") + } + // Expect the posts to be rendered. + if doc.Find(`[data-testid="postsTemplate"]`).Length() == 0 { + t.Error("expected posts to be rendered, but it wasn't") + } + // Expect both posts to be rendered. + if actualPostCount := doc.Find(`[data-testid="postsTemplatePost"]`).Length(); actualPostCount != len(testPosts) { + t.Fatalf("expected %d posts to be rendered, found %d", len(testPosts), actualPostCount) + } + // Expect the posts to contain the author name. + doc.Find(`[data-testid="postsTemplatePost"]`).Each(func(index int, sel *goquery.Selection) { + expectedName := testPosts[index].Name + if actualName := sel.Find(`[data-testid="postsTemplatePostName"]`).Text(); actualName != expectedName { + t.Errorf("expected name %q, got %q", actualName, expectedName) + } + expectedAuthor := testPosts[index].Author + if actualAuthor := sel.Find(`[data-testid="postsTemplatePostAuthor"]`).Text(); actualAuthor != expectedAuthor { + t.Errorf("expected author %q, got %q", actualAuthor, expectedAuthor) + } + }) +} + +func TestPostsHandler(t *testing.T) { + tests := []struct { + name string + postGetter func() (posts []Post, err error) + expectedStatus int + assert func(doc *goquery.Document) + }{ + { + name: "database errors result in a 500 error", + postGetter: func() (posts []Post, err error) { + return nil, errors.New("database error") + }, + expectedStatus: http.StatusInternalServerError, + assert: func(doc *goquery.Document) { + expected := "failed to retrieve posts\n" + if actual := doc.Text(); actual != expected { + t.Errorf("expected error message %q, got %q", expected, actual) + } + }, + }, + { + name: "database success renders the posts", + postGetter: func() (posts []Post, err error) { + return []Post{ + {Name: "Name1", Author: "Author1"}, + {Name: "Name2", Author: "Author2"}, + }, nil + }, + expectedStatus: http.StatusInternalServerError, + assert: func(doc *goquery.Document) { + if doc.Find(`[data-testid="postsTemplate"]`).Length() == 0 { + t.Error("expected posts to be rendered, but it wasn't") + } + }, + }, + } + for _, test := range tests { + // Arrange. + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, "/posts", nil) + + ph := NewPostsHandler() + ph.Log = log.New(io.Discard, "", 0) // Suppress logging. + ph.GetPosts = test.postGetter + + // Act. + ph.ServeHTTP(w, r) + doc, err := goquery.NewDocumentFromReader(w.Result().Body) + if err != nil { + t.Fatalf("failed to read template: %v", err) + } + + // Assert. + test.assert(doc) + } +} diff --git a/templ/examples/content-security-policy/main.go b/templ/examples/content-security-policy/main.go new file mode 100644 index 0000000..977a368 --- /dev/null +++ b/templ/examples/content-security-policy/main.go @@ -0,0 +1,68 @@ +package main + +import ( + "crypto/rand" + "fmt" + "math/big" + "net/http" + "os" + + "log/slog" + + "github.com/a-h/templ" +) + +func main() { + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + + // Create HTTP routes. + mux := http.NewServeMux() + mux.Handle("/", templ.Handler(template())) + + // Wrap the router with CSP middleware to apply the CSP nonce to templ scripts. + withCSPMiddleware := NewCSPMiddleware(log, mux) + + log.Info("Listening...", slog.String("addr", "127.0.0.1:7001")) + if err := http.ListenAndServe("127.0.0.1:7001", withCSPMiddleware); err != nil { + log.Error("failed to start server", slog.Any("error", err)) + } +} + +func NewCSPMiddleware(log *slog.Logger, next http.Handler) *CSPMiddleware { + return &CSPMiddleware{ + Log: log, + Next: next, + Size: 28, + } +} + +type CSPMiddleware struct { + Log *slog.Logger + Next http.Handler + Size int +} + +func (m *CSPMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + nonce, err := m.generateNonce() + if err != nil { + m.Log.Error("failed to generate nonce", slog.Any("error", err)) + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + ctx := templ.WithNonce(r.Context(), nonce) + w.Header().Add("Content-Security-Policy", fmt.Sprintf("script-src 'nonce-%s'", nonce)) + m.Next.ServeHTTP(w, r.WithContext(ctx)) +} + +func (m *CSPMiddleware) generateNonce() (string, error) { + const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, m.Size) + for i := 0; i < m.Size; i++ { + num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) + if err != nil { + return "", err + } + ret[i] = letters[num.Int64()] + } + return string(ret), nil +} diff --git a/templ/examples/content-security-policy/templates.templ b/templ/examples/content-security-policy/templates.templ new file mode 100644 index 0000000..c88808a --- /dev/null +++ b/templ/examples/content-security-policy/templates.templ @@ -0,0 +1,9 @@ +package main + +script sayHello() { + alert("Hello") +} + +templ template() { + @sayHello() +} diff --git a/templ/examples/content-security-policy/templates_templ.go b/templ/examples/content-security-policy/templates_templ.go new file mode 100644 index 0000000..e97a70b --- /dev/null +++ b/templ/examples/content-security-policy/templates_templ.go @@ -0,0 +1,50 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func sayHello() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_sayHello_6bd3`, + Function: `function __templ_sayHello_6bd3(){alert("Hello") +}`, + Call: templ.SafeScript(`__templ_sayHello_6bd3`), + CallInline: templ.SafeScriptInline(`__templ_sayHello_6bd3`), + } +} + +func template() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = sayHello().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/counter-basic/.dockerignore b/templ/examples/counter-basic/.dockerignore new file mode 100644 index 0000000..9414382 --- /dev/null +++ b/templ/examples/counter-basic/.dockerignore @@ -0,0 +1 @@ +Dockerfile diff --git a/templ/examples/counter-basic/Dockerfile b/templ/examples/counter-basic/Dockerfile new file mode 100644 index 0000000..67c6b33 --- /dev/null +++ b/templ/examples/counter-basic/Dockerfile @@ -0,0 +1,16 @@ +# Build. +FROM golang:1.20 AS build-stage +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download +COPY . /app +RUN CGO_ENABLED=0 GOOS=linux go build -o /entrypoint + +# Deploy. +FROM gcr.io/distroless/static-debian11 AS release-stage +WORKDIR / +COPY --chown=nonroot --from=build-stage /entrypoint /entrypoint +COPY --chown=nonroot --from=build-stage /app/assets /assets +EXPOSE 8080 +USER nonroot:nonroot +ENTRYPOINT ["/entrypoint"] diff --git a/templ/examples/counter-basic/README.md b/templ/examples/counter-basic/README.md new file mode 100644 index 0000000..84819c5 --- /dev/null +++ b/templ/examples/counter-basic/README.md @@ -0,0 +1,7 @@ +## Tasks + +### run + +```bash +templ generate --watch --proxy="http://localhost:8080" --cmd="go run ." +``` diff --git a/templ/examples/counter-basic/assets/bulma.css b/templ/examples/counter-basic/assets/bulma.css new file mode 100644 index 0000000..1dbfc86 --- /dev/null +++ b/templ/examples/counter-basic/assets/bulma.css @@ -0,0 +1,11851 @@ +/*! bulma.io v0.9.4 | MIT License | github.com/jgthms/bulma */ +/* Bulma Utilities */ +.button, .input, .textarea, .select select, .file-cta, +.file-name, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.5em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; +} + +.button:focus, .input:focus, .textarea:focus, .select select:focus, .file-cta:focus, +.file-name:focus, .pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus, +.pagination-ellipsis:focus, .is-focused.button, .is-focused.input, .is-focused.textarea, .select select.is-focused, .is-focused.file-cta, +.is-focused.file-name, .is-focused.pagination-previous, +.is-focused.pagination-next, +.is-focused.pagination-link, +.is-focused.pagination-ellipsis, .button:active, .input:active, .textarea:active, .select select:active, .file-cta:active, +.file-name:active, .pagination-previous:active, +.pagination-next:active, +.pagination-link:active, +.pagination-ellipsis:active, .is-active.button, .is-active.input, .is-active.textarea, .select select.is-active, .is-active.file-cta, +.is-active.file-name, .is-active.pagination-previous, +.is-active.pagination-next, +.is-active.pagination-link, +.is-active.pagination-ellipsis { + outline: none; +} + +.button[disabled], .input[disabled], .textarea[disabled], .select select[disabled], .file-cta[disabled], +.file-name[disabled], .pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled], +.pagination-ellipsis[disabled], +fieldset[disabled] .button, +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +.select fieldset[disabled] select, +fieldset[disabled] .file-cta, +fieldset[disabled] .file-name, +fieldset[disabled] .pagination-previous, +fieldset[disabled] .pagination-next, +fieldset[disabled] .pagination-link, +fieldset[disabled] .pagination-ellipsis { + cursor: not-allowed; +} + +.button, .file, .breadcrumb, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .tabs, .is-unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; +} + +.box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .block:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .message:not(:last-child), .pagination:not(:last-child), .tabs:not(:last-child) { + margin-bottom: 1.5rem; +} + +.delete, .modal-close { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 9999px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; +} + +.delete::before, .modal-close::before, .delete::after, .modal-close::after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} + +.delete::before, .modal-close::before { + height: 2px; + width: 50%; +} + +.delete::after, .modal-close::after { + height: 50%; + width: 2px; +} + +.delete:hover, .modal-close:hover, .delete:focus, .modal-close:focus { + background-color: rgba(10, 10, 10, 0.3); +} + +.delete:active, .modal-close:active { + background-color: rgba(10, 10, 10, 0.4); +} + +.is-small.delete, .is-small.modal-close { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} + +.is-medium.delete, .is-medium.modal-close { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} + +.is-large.delete, .is-large.modal-close { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} + +.button.is-loading::after, .loader, .select.is-loading::after, .control.is-loading::after { + -webkit-animation: spinAround 500ms infinite linear; + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 9999px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} + +.image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio, .modal, .modal-background, .is-overlay, .hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.navbar-burger { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + color: currentColor; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; +} + +/* Bulma Base */ +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +ul { + list-style: none; +} + +button, +input, +select, +textarea { + margin: 0; +} + +html { + box-sizing: border-box; +} + +*, *::before, *::after { + box-sizing: inherit; +} + +img, +video { + height: auto; + max-width: 100%; +} + +iframe { + border: 0; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} + +td:not([align]), +th:not([align]) { + text-align: inherit; +} + +html { + background-color: white; + font-size: 16px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; +} + +body, +button, +input, +optgroup, +select, +textarea { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; +} + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: monospace; +} + +body { + color: #4a4a4a; + font-size: 1em; + font-weight: 400; + line-height: 1.5; +} + +a { + color: #485fc7; + cursor: pointer; + text-decoration: none; +} + +a strong { + color: currentColor; +} + +a:hover { + color: #363636; +} + +code { + background-color: whitesmoke; + color: #da1039; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; +} + +hr { + background-color: whitesmoke; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; +} + +img { + height: auto; + max-width: 100%; +} + +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; +} + +small { + font-size: 0.875em; +} + +span { + font-style: inherit; + font-weight: inherit; +} + +strong { + color: #363636; + font-weight: 700; +} + +fieldset { + border: none; +} + +pre { + -webkit-overflow-scrolling: touch; + background-color: whitesmoke; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; +} + +pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; +} + +table td, +table th { + vertical-align: top; +} + +table td:not([align]), +table th:not([align]) { + text-align: inherit; +} + +table th { + color: #363636; +} + +@-webkit-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} + +@keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} + +/* Bulma Elements */ +.box { + background-color: white; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + display: block; + padding: 1.25rem; +} + +a.box:hover, a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px #485fc7; +} + +a.box:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2), 0 0 0 1px #485fc7; +} + +.button { + background-color: white; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.5em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.5em - 1px); + text-align: center; + white-space: nowrap; +} + +.button strong { + color: inherit; +} + +.button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; +} + +.button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; +} + +.button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); +} + +.button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); +} + +.button:hover, .button.is-hovered { + border-color: #b5b5b5; + color: #363636; +} + +.button:focus, .button.is-focused { + border-color: #485fc7; + color: #363636; +} + +.button:focus:not(:active), .button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.button:active, .button.is-active { + border-color: #4a4a4a; + color: #363636; +} + +.button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; +} + +.button.is-text:hover, .button.is-text.is-hovered, .button.is-text:focus, .button.is-text.is-focused { + background-color: whitesmoke; + color: #363636; +} + +.button.is-text:active, .button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; +} + +.button.is-text[disabled], +fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} + +.button.is-ghost { + background: none; + border-color: transparent; + color: #485fc7; + text-decoration: none; +} + +.button.is-ghost:hover, .button.is-ghost.is-hovered { + color: #485fc7; + text-decoration: underline; +} + +.button.is-white { + background-color: white; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:hover, .button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:focus, .button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.button.is-white:active, .button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white[disabled], +fieldset[disabled] .button.is-white { + background-color: white; + border-color: white; + box-shadow: none; +} + +.button.is-white.is-inverted { + background-color: #0a0a0a; + color: white; +} + +.button.is-white.is-inverted:hover, .button.is-white.is-inverted.is-hovered { + background-color: black; +} + +.button.is-white.is-inverted[disabled], +fieldset[disabled] .button.is-white.is-inverted { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: white; +} + +.button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-white.is-outlined { + background-color: transparent; + border-color: white; + color: white; +} + +.button.is-white.is-outlined:hover, .button.is-white.is-outlined.is-hovered, .button.is-white.is-outlined:focus, .button.is-white.is-outlined.is-focused { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent white white !important; +} + +.button.is-white.is-outlined.is-loading:hover::after, .button.is-white.is-outlined.is-loading.is-hovered::after, .button.is-white.is-outlined.is-loading:focus::after, .button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-white.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; +} + +.button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} + +.button.is-white.is-inverted.is-outlined:hover, .button.is-white.is-inverted.is-outlined.is-hovered, .button.is-white.is-inverted.is-outlined:focus, .button.is-white.is-inverted.is-outlined.is-focused { + background-color: #0a0a0a; + color: white; +} + +.button.is-white.is-inverted.is-outlined.is-loading:hover::after, .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-white.is-inverted.is-outlined.is-loading:focus::after, .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; +} + +.button.is-white.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: white; +} + +.button.is-black:hover, .button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: white; +} + +.button.is-black:focus, .button.is-black.is-focused { + border-color: transparent; + color: white; +} + +.button.is-black:focus:not(:active), .button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.button.is-black:active, .button.is-black.is-active { + background-color: black; + border-color: transparent; + color: white; +} + +.button.is-black[disabled], +fieldset[disabled] .button.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + box-shadow: none; +} + +.button.is-black.is-inverted { + background-color: white; + color: #0a0a0a; +} + +.button.is-black.is-inverted:hover, .button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-black.is-inverted[disabled], +fieldset[disabled] .button.is-black.is-inverted { + background-color: white; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black.is-loading::after { + border-color: transparent transparent white white !important; +} + +.button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} + +.button.is-black.is-outlined:hover, .button.is-black.is-outlined.is-hovered, .button.is-black.is-outlined:focus, .button.is-black.is-outlined.is-focused { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-black.is-outlined.is-loading:hover::after, .button.is-black.is-outlined.is-loading.is-hovered::after, .button.is-black.is-outlined.is-loading:focus::after, .button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; +} + +.button.is-black.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + color: white; +} + +.button.is-black.is-inverted.is-outlined:hover, .button.is-black.is-inverted.is-outlined.is-hovered, .button.is-black.is-inverted.is-outlined:focus, .button.is-black.is-inverted.is-outlined.is-focused { + background-color: white; + color: #0a0a0a; +} + +.button.is-black.is-inverted.is-outlined.is-loading:hover::after, .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-black.is-inverted.is-outlined.is-loading:focus::after, .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-black.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; +} + +.button.is-light { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:hover, .button.is-light.is-hovered { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:focus, .button.is-light.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:focus:not(:active), .button.is-light.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.button.is-light:active, .button.is-light.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light[disabled], +fieldset[disabled] .button.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; +} + +.button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.button.is-light.is-inverted:hover, .button.is-light.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-inverted[disabled], +fieldset[disabled] .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: whitesmoke; +} + +.button.is-light.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; +} + +.button.is-light.is-outlined:hover, .button.is-light.is-outlined.is-hovered, .button.is-light.is-outlined:focus, .button.is-light.is-outlined.is-focused { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-outlined.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; +} + +.button.is-light.is-outlined.is-loading:hover::after, .button.is-light.is-outlined.is-loading.is-hovered::after, .button.is-light.is-outlined.is-loading:focus::after, .button.is-light.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-light.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; +} + +.button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-inverted.is-outlined:hover, .button.is-light.is-inverted.is-outlined.is-hovered, .button.is-light.is-inverted.is-outlined:focus, .button.is-light.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.button.is-light.is-inverted.is-outlined.is-loading:hover::after, .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-light.is-inverted.is-outlined.is-loading:focus::after, .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent whitesmoke whitesmoke !important; +} + +.button.is-light.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; +} + +.button.is-dark:hover, .button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} + +.button.is-dark:focus, .button.is-dark.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-dark:focus:not(:active), .button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.button.is-dark:active, .button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; +} + +.button.is-dark[disabled], +fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: #363636; + box-shadow: none; +} + +.button.is-dark.is-inverted { + background-color: #fff; + color: #363636; +} + +.button.is-dark.is-inverted:hover, .button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-dark.is-inverted[disabled], +fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; +} + +.button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} + +.button.is-dark.is-outlined:hover, .button.is-dark.is-outlined.is-hovered, .button.is-dark.is-outlined:focus, .button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; +} + +.button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} + +.button.is-dark.is-outlined.is-loading:hover::after, .button.is-dark.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-outlined.is-loading:focus::after, .button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-dark.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} + +.button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-dark.is-inverted.is-outlined:hover, .button.is-dark.is-inverted.is-outlined.is-hovered, .button.is-dark.is-inverted.is-outlined:focus, .button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; +} + +.button.is-dark.is-inverted.is-outlined.is-loading:hover::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-inverted.is-outlined.is-loading:focus::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} + +.button.is-dark.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-primary { + background-color: #00d1b2; + border-color: transparent; + color: #fff; +} + +.button.is-primary:hover, .button.is-primary.is-hovered { + background-color: #00c4a7; + border-color: transparent; + color: #fff; +} + +.button.is-primary:focus, .button.is-primary.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-primary:focus:not(:active), .button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.button.is-primary:active, .button.is-primary.is-active { + background-color: #00b89c; + border-color: transparent; + color: #fff; +} + +.button.is-primary[disabled], +fieldset[disabled] .button.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + box-shadow: none; +} + +.button.is-primary.is-inverted { + background-color: #fff; + color: #00d1b2; +} + +.button.is-primary.is-inverted:hover, .button.is-primary.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-primary.is-inverted[disabled], +fieldset[disabled] .button.is-primary.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #00d1b2; +} + +.button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + color: #00d1b2; +} + +.button.is-primary.is-outlined:hover, .button.is-primary.is-outlined.is-hovered, .button.is-primary.is-outlined:focus, .button.is-primary.is-outlined.is-focused { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; +} + +.button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; +} + +.button.is-primary.is-outlined.is-loading:hover::after, .button.is-primary.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-outlined.is-loading:focus::after, .button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-primary.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + box-shadow: none; + color: #00d1b2; +} + +.button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-primary.is-inverted.is-outlined:hover, .button.is-primary.is-inverted.is-outlined.is-hovered, .button.is-primary.is-inverted.is-outlined:focus, .button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #00d1b2; +} + +.button.is-primary.is-inverted.is-outlined.is-loading:hover::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-inverted.is-outlined.is-loading:focus::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; +} + +.button.is-primary.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.button.is-primary.is-light:hover, .button.is-primary.is-light.is-hovered { + background-color: #defffa; + border-color: transparent; + color: #00947e; +} + +.button.is-primary.is-light:active, .button.is-primary.is-light.is-active { + background-color: #d1fff8; + border-color: transparent; + color: #00947e; +} + +.button.is-link { + background-color: #485fc7; + border-color: transparent; + color: #fff; +} + +.button.is-link:hover, .button.is-link.is-hovered { + background-color: #3e56c4; + border-color: transparent; + color: #fff; +} + +.button.is-link:focus, .button.is-link.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-link:focus:not(:active), .button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.button.is-link:active, .button.is-link.is-active { + background-color: #3a51bb; + border-color: transparent; + color: #fff; +} + +.button.is-link[disabled], +fieldset[disabled] .button.is-link { + background-color: #485fc7; + border-color: #485fc7; + box-shadow: none; +} + +.button.is-link.is-inverted { + background-color: #fff; + color: #485fc7; +} + +.button.is-link.is-inverted:hover, .button.is-link.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-link.is-inverted[disabled], +fieldset[disabled] .button.is-link.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #485fc7; +} + +.button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-link.is-outlined { + background-color: transparent; + border-color: #485fc7; + color: #485fc7; +} + +.button.is-link.is-outlined:hover, .button.is-link.is-outlined.is-hovered, .button.is-link.is-outlined:focus, .button.is-link.is-outlined.is-focused { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #485fc7 #485fc7 !important; +} + +.button.is-link.is-outlined.is-loading:hover::after, .button.is-link.is-outlined.is-loading.is-hovered::after, .button.is-link.is-outlined.is-loading:focus::after, .button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-link.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #485fc7; + box-shadow: none; + color: #485fc7; +} + +.button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-link.is-inverted.is-outlined:hover, .button.is-link.is-inverted.is-outlined.is-hovered, .button.is-link.is-inverted.is-outlined:focus, .button.is-link.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #485fc7; +} + +.button.is-link.is-inverted.is-outlined.is-loading:hover::after, .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-link.is-inverted.is-outlined.is-loading:focus::after, .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #485fc7 #485fc7 !important; +} + +.button.is-link.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.button.is-link.is-light:hover, .button.is-link.is-light.is-hovered { + background-color: #e6e9f7; + border-color: transparent; + color: #3850b7; +} + +.button.is-link.is-light:active, .button.is-link.is-light.is-active { + background-color: #dce0f4; + border-color: transparent; + color: #3850b7; +} + +.button.is-info { + background-color: #3e8ed0; + border-color: transparent; + color: #fff; +} + +.button.is-info:hover, .button.is-info.is-hovered { + background-color: #3488ce; + border-color: transparent; + color: #fff; +} + +.button.is-info:focus, .button.is-info.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-info:focus:not(:active), .button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.button.is-info:active, .button.is-info.is-active { + background-color: #3082c5; + border-color: transparent; + color: #fff; +} + +.button.is-info[disabled], +fieldset[disabled] .button.is-info { + background-color: #3e8ed0; + border-color: #3e8ed0; + box-shadow: none; +} + +.button.is-info.is-inverted { + background-color: #fff; + color: #3e8ed0; +} + +.button.is-info.is-inverted:hover, .button.is-info.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-info.is-inverted[disabled], +fieldset[disabled] .button.is-info.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3e8ed0; +} + +.button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-info.is-outlined { + background-color: transparent; + border-color: #3e8ed0; + color: #3e8ed0; +} + +.button.is-info.is-outlined:hover, .button.is-info.is-outlined.is-hovered, .button.is-info.is-outlined:focus, .button.is-info.is-outlined.is-focused { + background-color: #3e8ed0; + border-color: #3e8ed0; + color: #fff; +} + +.button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #3e8ed0 #3e8ed0 !important; +} + +.button.is-info.is-outlined.is-loading:hover::after, .button.is-info.is-outlined.is-loading.is-hovered::after, .button.is-info.is-outlined.is-loading:focus::after, .button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-info.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #3e8ed0; + box-shadow: none; + color: #3e8ed0; +} + +.button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-info.is-inverted.is-outlined:hover, .button.is-info.is-inverted.is-outlined.is-hovered, .button.is-info.is-inverted.is-outlined:focus, .button.is-info.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3e8ed0; +} + +.button.is-info.is-inverted.is-outlined.is-loading:hover::after, .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-info.is-inverted.is-outlined.is-loading:focus::after, .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3e8ed0 #3e8ed0 !important; +} + +.button.is-info.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.button.is-info.is-light:hover, .button.is-info.is-light.is-hovered { + background-color: #e4eff9; + border-color: transparent; + color: #296fa8; +} + +.button.is-info.is-light:active, .button.is-info.is-light.is-active { + background-color: #dae9f6; + border-color: transparent; + color: #296fa8; +} + +.button.is-success { + background-color: #48c78e; + border-color: transparent; + color: #fff; +} + +.button.is-success:hover, .button.is-success.is-hovered { + background-color: #3ec487; + border-color: transparent; + color: #fff; +} + +.button.is-success:focus, .button.is-success.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-success:focus:not(:active), .button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.button.is-success:active, .button.is-success.is-active { + background-color: #3abb81; + border-color: transparent; + color: #fff; +} + +.button.is-success[disabled], +fieldset[disabled] .button.is-success { + background-color: #48c78e; + border-color: #48c78e; + box-shadow: none; +} + +.button.is-success.is-inverted { + background-color: #fff; + color: #48c78e; +} + +.button.is-success.is-inverted:hover, .button.is-success.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-success.is-inverted[disabled], +fieldset[disabled] .button.is-success.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #48c78e; +} + +.button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-success.is-outlined { + background-color: transparent; + border-color: #48c78e; + color: #48c78e; +} + +.button.is-success.is-outlined:hover, .button.is-success.is-outlined.is-hovered, .button.is-success.is-outlined:focus, .button.is-success.is-outlined.is-focused { + background-color: #48c78e; + border-color: #48c78e; + color: #fff; +} + +.button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #48c78e #48c78e !important; +} + +.button.is-success.is-outlined.is-loading:hover::after, .button.is-success.is-outlined.is-loading.is-hovered::after, .button.is-success.is-outlined.is-loading:focus::after, .button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-success.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c78e; + box-shadow: none; + color: #48c78e; +} + +.button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-success.is-inverted.is-outlined:hover, .button.is-success.is-inverted.is-outlined.is-hovered, .button.is-success.is-inverted.is-outlined:focus, .button.is-success.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #48c78e; +} + +.button.is-success.is-inverted.is-outlined.is-loading:hover::after, .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-success.is-inverted.is-outlined.is-loading:focus::after, .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #48c78e #48c78e !important; +} + +.button.is-success.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.button.is-success.is-light:hover, .button.is-success.is-light.is-hovered { + background-color: #e6f7ef; + border-color: transparent; + color: #257953; +} + +.button.is-success.is-light:active, .button.is-success.is-light.is-active { + background-color: #dcf4e9; + border-color: transparent; + color: #257953; +} + +.button.is-warning { + background-color: #ffe08a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:hover, .button.is-warning.is-hovered { + background-color: #ffdc7d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:focus, .button.is-warning.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:focus:not(:active), .button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.button.is-warning:active, .button.is-warning.is-active { + background-color: #ffd970; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning[disabled], +fieldset[disabled] .button.is-warning { + background-color: #ffe08a; + border-color: #ffe08a; + box-shadow: none; +} + +.button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.button.is-warning.is-inverted:hover, .button.is-warning.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-inverted[disabled], +fieldset[disabled] .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: #ffe08a; +} + +.button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffe08a; + color: #ffe08a; +} + +.button.is-warning.is-outlined:hover, .button.is-warning.is-outlined.is-hovered, .button.is-warning.is-outlined:focus, .button.is-warning.is-outlined.is-focused { + background-color: #ffe08a; + border-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffe08a #ffe08a !important; +} + +.button.is-warning.is-outlined.is-loading:hover::after, .button.is-warning.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-outlined.is-loading:focus::after, .button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-warning.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffe08a; + box-shadow: none; + color: #ffe08a; +} + +.button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-inverted.is-outlined:hover, .button.is-warning.is-inverted.is-outlined.is-hovered, .button.is-warning.is-inverted.is-outlined:focus, .button.is-warning.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.button.is-warning.is-inverted.is-outlined.is-loading:hover::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-inverted.is-outlined.is-loading:focus::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ffe08a #ffe08a !important; +} + +.button.is-warning.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.button.is-warning.is-light:hover, .button.is-warning.is-light.is-hovered { + background-color: #fff6de; + border-color: transparent; + color: #946c00; +} + +.button.is-warning.is-light:active, .button.is-warning.is-light.is-active { + background-color: #fff3d1; + border-color: transparent; + color: #946c00; +} + +.button.is-danger { + background-color: #f14668; + border-color: transparent; + color: #fff; +} + +.button.is-danger:hover, .button.is-danger.is-hovered { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} + +.button.is-danger:focus, .button.is-danger.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-danger:focus:not(:active), .button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.button.is-danger:active, .button.is-danger.is-active { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} + +.button.is-danger[disabled], +fieldset[disabled] .button.is-danger { + background-color: #f14668; + border-color: #f14668; + box-shadow: none; +} + +.button.is-danger.is-inverted { + background-color: #fff; + color: #f14668; +} + +.button.is-danger.is-inverted:hover, .button.is-danger.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-danger.is-inverted[disabled], +fieldset[disabled] .button.is-danger.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #f14668; +} + +.button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + color: #f14668; +} + +.button.is-danger.is-outlined:hover, .button.is-danger.is-outlined.is-hovered, .button.is-danger.is-outlined:focus, .button.is-danger.is-outlined.is-focused { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} + +.button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #f14668 #f14668 !important; +} + +.button.is-danger.is-outlined.is-loading:hover::after, .button.is-danger.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-outlined.is-loading:focus::after, .button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-danger.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + box-shadow: none; + color: #f14668; +} + +.button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-danger.is-inverted.is-outlined:hover, .button.is-danger.is-inverted.is-outlined.is-hovered, .button.is-danger.is-inverted.is-outlined:focus, .button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #f14668; +} + +.button.is-danger.is-inverted.is-outlined.is-loading:hover::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-inverted.is-outlined.is-loading:focus::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f14668 #f14668 !important; +} + +.button.is-danger.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.button.is-danger.is-light:hover, .button.is-danger.is-light.is-hovered { + background-color: #fde0e6; + border-color: transparent; + color: #cc0f35; +} + +.button.is-danger.is-light:active, .button.is-danger.is-light.is-active { + background-color: #fcd4dc; + border-color: transparent; + color: #cc0f35; +} + +.button.is-small { + font-size: 0.75rem; +} + +.button.is-small:not(.is-rounded) { + border-radius: 2px; +} + +.button.is-normal { + font-size: 1rem; +} + +.button.is-medium { + font-size: 1.25rem; +} + +.button.is-large { + font-size: 1.5rem; +} + +.button[disabled], +fieldset[disabled] .button { + background-color: white; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; +} + +.button.is-fullwidth { + display: flex; + width: 100%; +} + +.button.is-loading { + color: transparent !important; + pointer-events: none; +} + +.button.is-loading::after { + position: absolute; + left: calc(50% - (1em * 0.5)); + top: calc(50% - (1em * 0.5)); + position: absolute !important; +} + +.button.is-static { + background-color: whitesmoke; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; +} + +.button.is-rounded { + border-radius: 9999px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); +} + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.buttons .button { + margin-bottom: 0.5rem; +} + +.buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; +} + +.buttons:last-child { + margin-bottom: -0.5rem; +} + +.buttons:not(:last-child) { + margin-bottom: 1rem; +} + +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + font-size: 0.75rem; +} + +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded) { + border-radius: 2px; +} + +.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; +} + +.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; +} + +.buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; +} + +.buttons.has-addons .button:last-child { + margin-right: 0; +} + +.buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; +} + +.buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; +} + +.buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; +} + +.buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.buttons.is-centered { + justify-content: center; +} + +.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} + +.buttons.is-right { + justify-content: flex-end; +} + +.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} + +@media screen and (max-width: 768px) { + .button.is-responsive.is-small { + font-size: 0.5625rem; + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: 0.65625rem; + } + .button.is-responsive.is-medium { + font-size: 0.75rem; + } + .button.is-responsive.is-large { + font-size: 1rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .button.is-responsive.is-small { + font-size: 0.65625rem; + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: 0.75rem; + } + .button.is-responsive.is-medium { + font-size: 1rem; + } + .button.is-responsive.is-large { + font-size: 1.25rem; + } +} + +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; +} + +.container.is-fluid { + max-width: none !important; + padding-left: 32px; + padding-right: 32px; + width: 100%; +} + +@media screen and (min-width: 1024px) { + .container { + max-width: 960px; + } +} + +@media screen and (max-width: 1215px) { + .container.is-widescreen:not(.is-max-desktop) { + max-width: 1152px; + } +} + +@media screen and (max-width: 1407px) { + .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} + +@media screen and (min-width: 1216px) { + .container:not(.is-max-desktop) { + max-width: 1152px; + } +} + +@media screen and (min-width: 1408px) { + .container:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} + +.content li + li { + margin-top: 0.25em; +} + +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; +} + +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 600; + line-height: 1.125; +} + +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; +} + +.content h1:not(:first-child) { + margin-top: 1em; +} + +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; +} + +.content h2:not(:first-child) { + margin-top: 1.1428em; +} + +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; +} + +.content h3:not(:first-child) { + margin-top: 1.3333em; +} + +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; +} + +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; +} + +.content h6 { + font-size: 1em; + margin-bottom: 1em; +} + +.content blockquote { + background-color: whitesmoke; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; +} + +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; +} + +.content ol:not([type]) { + list-style-type: decimal; +} + +.content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; +} + +.content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; +} + +.content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; +} + +.content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; +} + +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; +} + +.content ul ul { + list-style-type: circle; + margin-top: 0.5em; +} + +.content ul ul ul { + list-style-type: square; +} + +.content dd { + margin-left: 2em; +} + +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; +} + +.content figure:not(:first-child) { + margin-top: 2em; +} + +.content figure:not(:last-child) { + margin-bottom: 2em; +} + +.content figure img { + display: inline-block; +} + +.content figure figcaption { + font-style: italic; +} + +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; +} + +.content sup, +.content sub { + font-size: 75%; +} + +.content table { + width: 100%; +} + +.content table td, +.content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.content table th { + color: #363636; +} + +.content table th:not([align]) { + text-align: inherit; +} + +.content table thead td, +.content table thead th { + border-width: 0 0 2px; + color: #363636; +} + +.content table tfoot td, +.content table tfoot th { + border-width: 2px 0 0; + color: #363636; +} + +.content table tbody tr:last-child td, +.content table tbody tr:last-child th { + border-bottom-width: 0; +} + +.content .tabs li + li { + margin-top: 0; +} + +.content.is-small { + font-size: 0.75rem; +} + +.content.is-normal { + font-size: 1rem; +} + +.content.is-medium { + font-size: 1.25rem; +} + +.content.is-large { + font-size: 1.5rem; +} + +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; +} + +.icon.is-small { + height: 1rem; + width: 1rem; +} + +.icon.is-medium { + height: 2rem; + width: 2rem; +} + +.icon.is-large { + height: 3rem; + width: 3rem; +} + +.icon-text { + align-items: flex-start; + color: inherit; + display: inline-flex; + flex-wrap: wrap; + line-height: 1.5rem; + vertical-align: top; +} + +.icon-text .icon { + flex-grow: 0; + flex-shrink: 0; +} + +.icon-text .icon:not(:last-child) { + margin-right: 0.25em; +} + +.icon-text .icon:not(:first-child) { + margin-left: 0.25em; +} + +div.icon-text { + display: flex; +} + +.image { + display: block; + position: relative; +} + +.image img { + display: block; + height: auto; + width: 100%; +} + +.image img.is-rounded { + border-radius: 9999px; +} + +.image.is-fullwidth { + width: 100%; +} + +.image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio { + height: 100%; + width: 100%; +} + +.image.is-square, .image.is-1by1 { + padding-top: 100%; +} + +.image.is-5by4 { + padding-top: 80%; +} + +.image.is-4by3 { + padding-top: 75%; +} + +.image.is-3by2 { + padding-top: 66.6666%; +} + +.image.is-5by3 { + padding-top: 60%; +} + +.image.is-16by9 { + padding-top: 56.25%; +} + +.image.is-2by1 { + padding-top: 50%; +} + +.image.is-3by1 { + padding-top: 33.3333%; +} + +.image.is-4by5 { + padding-top: 125%; +} + +.image.is-3by4 { + padding-top: 133.3333%; +} + +.image.is-2by3 { + padding-top: 150%; +} + +.image.is-3by5 { + padding-top: 166.6666%; +} + +.image.is-9by16 { + padding-top: 177.7777%; +} + +.image.is-1by2 { + padding-top: 200%; +} + +.image.is-1by3 { + padding-top: 300%; +} + +.image.is-16x16 { + height: 16px; + width: 16px; +} + +.image.is-24x24 { + height: 24px; + width: 24px; +} + +.image.is-32x32 { + height: 32px; + width: 32px; +} + +.image.is-48x48 { + height: 48px; + width: 48px; +} + +.image.is-64x64 { + height: 64px; + width: 64px; +} + +.image.is-96x96 { + height: 96px; + width: 96px; +} + +.image.is-128x128 { + height: 128px; + width: 128px; +} + +.notification { + background-color: whitesmoke; + border-radius: 4px; + position: relative; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; +} + +.notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} + +.notification strong { + color: currentColor; +} + +.notification code, +.notification pre { + background: white; +} + +.notification pre code { + background: transparent; +} + +.notification > .delete { + right: 0.5rem; + position: absolute; + top: 0.5rem; +} + +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} + +.notification.is-white { + background-color: white; + color: #0a0a0a; +} + +.notification.is-black { + background-color: #0a0a0a; + color: white; +} + +.notification.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.notification.is-dark { + background-color: #363636; + color: #fff; +} + +.notification.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.notification.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.notification.is-link { + background-color: #485fc7; + color: #fff; +} + +.notification.is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.notification.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.notification.is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.notification.is-success { + background-color: #48c78e; + color: #fff; +} + +.notification.is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.notification.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.notification.is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.notification.is-danger { + background-color: #f14668; + color: #fff; +} + +.notification.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 9999px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; +} + +.progress::-webkit-progress-bar { + background-color: #ededed; +} + +.progress::-webkit-progress-value { + background-color: #4a4a4a; +} + +.progress::-moz-progress-bar { + background-color: #4a4a4a; +} + +.progress::-ms-fill { + background-color: #4a4a4a; + border: none; +} + +.progress.is-white::-webkit-progress-value { + background-color: white; +} + +.progress.is-white::-moz-progress-bar { + background-color: white; +} + +.progress.is-white::-ms-fill { + background-color: white; +} + +.progress.is-white:indeterminate { + background-image: linear-gradient(to right, white 30%, #ededed 30%); +} + +.progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; +} + +.progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; +} + +.progress.is-black::-ms-fill { + background-color: #0a0a0a; +} + +.progress.is-black:indeterminate { + background-image: linear-gradient(to right, #0a0a0a 30%, #ededed 30%); +} + +.progress.is-light::-webkit-progress-value { + background-color: whitesmoke; +} + +.progress.is-light::-moz-progress-bar { + background-color: whitesmoke; +} + +.progress.is-light::-ms-fill { + background-color: whitesmoke; +} + +.progress.is-light:indeterminate { + background-image: linear-gradient(to right, whitesmoke 30%, #ededed 30%); +} + +.progress.is-dark::-webkit-progress-value { + background-color: #363636; +} + +.progress.is-dark::-moz-progress-bar { + background-color: #363636; +} + +.progress.is-dark::-ms-fill { + background-color: #363636; +} + +.progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); +} + +.progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; +} + +.progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; +} + +.progress.is-primary::-ms-fill { + background-color: #00d1b2; +} + +.progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #00d1b2 30%, #ededed 30%); +} + +.progress.is-link::-webkit-progress-value { + background-color: #485fc7; +} + +.progress.is-link::-moz-progress-bar { + background-color: #485fc7; +} + +.progress.is-link::-ms-fill { + background-color: #485fc7; +} + +.progress.is-link:indeterminate { + background-image: linear-gradient(to right, #485fc7 30%, #ededed 30%); +} + +.progress.is-info::-webkit-progress-value { + background-color: #3e8ed0; +} + +.progress.is-info::-moz-progress-bar { + background-color: #3e8ed0; +} + +.progress.is-info::-ms-fill { + background-color: #3e8ed0; +} + +.progress.is-info:indeterminate { + background-image: linear-gradient(to right, #3e8ed0 30%, #ededed 30%); +} + +.progress.is-success::-webkit-progress-value { + background-color: #48c78e; +} + +.progress.is-success::-moz-progress-bar { + background-color: #48c78e; +} + +.progress.is-success::-ms-fill { + background-color: #48c78e; +} + +.progress.is-success:indeterminate { + background-image: linear-gradient(to right, #48c78e 30%, #ededed 30%); +} + +.progress.is-warning::-webkit-progress-value { + background-color: #ffe08a; +} + +.progress.is-warning::-moz-progress-bar { + background-color: #ffe08a; +} + +.progress.is-warning::-ms-fill { + background-color: #ffe08a; +} + +.progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ffe08a 30%, #ededed 30%); +} + +.progress.is-danger::-webkit-progress-value { + background-color: #f14668; +} + +.progress.is-danger::-moz-progress-bar { + background-color: #f14668; +} + +.progress.is-danger::-ms-fill { + background-color: #f14668; +} + +.progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #f14668 30%, #ededed 30%); +} + +.progress:indeterminate { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-name: moveIndeterminate; + animation-name: moveIndeterminate; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #4a4a4a 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; +} + +.progress:indeterminate::-webkit-progress-bar { + background-color: transparent; +} + +.progress:indeterminate::-moz-progress-bar { + background-color: transparent; +} + +.progress:indeterminate::-ms-fill { + animation-name: none; +} + +.progress.is-small { + height: 0.75rem; +} + +.progress.is-medium { + height: 1.25rem; +} + +.progress.is-large { + height: 1.5rem; +} + +@-webkit-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} + +@keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} + +.table { + background-color: white; + color: #363636; +} + +.table td, +.table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.table td.is-white, +.table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.table td.is-black, +.table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.table td.is-light, +.table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.table td.is-dark, +.table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; +} + +.table td.is-primary, +.table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; +} + +.table td.is-link, +.table th.is-link { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.table td.is-info, +.table th.is-info { + background-color: #3e8ed0; + border-color: #3e8ed0; + color: #fff; +} + +.table td.is-success, +.table th.is-success { + background-color: #48c78e; + border-color: #48c78e; + color: #fff; +} + +.table td.is-warning, +.table th.is-warning { + background-color: #ffe08a; + border-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.table td.is-danger, +.table th.is-danger { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} + +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} + +.table td.is-selected, +.table th.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table td.is-selected a, +.table td.is-selected strong, +.table th.is-selected a, +.table th.is-selected strong { + color: currentColor; +} + +.table td.is-vcentered, +.table th.is-vcentered { + vertical-align: middle; +} + +.table th { + color: #363636; +} + +.table th:not([align]) { + text-align: left; +} + +.table tr.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} + +.table tr.is-selected td, +.table tr.is-selected th { + border-color: #fff; + color: currentColor; +} + +.table thead { + background-color: transparent; +} + +.table thead td, +.table thead th { + border-width: 0 0 2px; + color: #363636; +} + +.table tfoot { + background-color: transparent; +} + +.table tfoot td, +.table tfoot th { + border-width: 2px 0 0; + color: #363636; +} + +.table tbody { + background-color: transparent; +} + +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} + +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} + +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} + +.table.is-fullwidth { + width: 100%; +} + +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} + +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} + +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: whitesmoke; +} + +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} + +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; +} + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} + +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.tags .tag { + margin-bottom: 0.5rem; +} + +.tags .tag:not(:last-child) { + margin-right: 0.5rem; +} + +.tags:last-child { + margin-bottom: -0.5rem; +} + +.tags:not(:last-child) { + margin-bottom: 1rem; +} + +.tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; +} + +.tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; +} + +.tags.is-centered { + justify-content: center; +} + +.tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.tags.is-right { + justify-content: flex-end; +} + +.tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; +} + +.tags.is-right .tag:not(:last-child) { + margin-right: 0; +} + +.tags.has-addons .tag { + margin-right: 0; +} + +.tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.tags.has-addons .tag:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.tag:not(body) { + align-items: center; + background-color: whitesmoke; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; +} + +.tag:not(body).is-white { + background-color: white; + color: #0a0a0a; +} + +.tag:not(body).is-black { + background-color: #0a0a0a; + color: white; +} + +.tag:not(body).is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.tag:not(body).is-dark { + background-color: #363636; + color: #fff; +} + +.tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; +} + +.tag:not(body).is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.tag:not(body).is-link { + background-color: #485fc7; + color: #fff; +} + +.tag:not(body).is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.tag:not(body).is-info { + background-color: #3e8ed0; + color: #fff; +} + +.tag:not(body).is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.tag:not(body).is-success { + background-color: #48c78e; + color: #fff; +} + +.tag:not(body).is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.tag:not(body).is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.tag:not(body).is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.tag:not(body).is-danger { + background-color: #f14668; + color: #fff; +} + +.tag:not(body).is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.tag:not(body).is-normal { + font-size: 0.75rem; +} + +.tag:not(body).is-medium { + font-size: 1rem; +} + +.tag:not(body).is-large { + font-size: 1.25rem; +} + +.tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; +} + +.tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; +} + +.tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; +} + +.tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; +} + +.tag:not(body).is-delete::before, .tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} + +.tag:not(body).is-delete::before { + height: 1px; + width: 50%; +} + +.tag:not(body).is-delete::after { + height: 50%; + width: 1px; +} + +.tag:not(body).is-delete:hover, .tag:not(body).is-delete:focus { + background-color: #e8e8e8; +} + +.tag:not(body).is-delete:active { + background-color: #dbdbdb; +} + +.tag:not(body).is-rounded { + border-radius: 9999px; +} + +a.tag:hover { + text-decoration: underline; +} + +.title, +.subtitle { + word-break: break-word; +} + +.title em, +.title span, +.subtitle em, +.subtitle span { + font-weight: inherit; +} + +.title sub, +.subtitle sub { + font-size: 0.75em; +} + +.title sup, +.subtitle sup { + font-size: 0.75em; +} + +.title .tag, +.subtitle .tag { + vertical-align: middle; +} + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; +} + +.title strong { + color: inherit; + font-weight: inherit; +} + +.title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; +} + +.title.is-1 { + font-size: 3rem; +} + +.title.is-2 { + font-size: 2.5rem; +} + +.title.is-3 { + font-size: 2rem; +} + +.title.is-4 { + font-size: 1.5rem; +} + +.title.is-5 { + font-size: 1.25rem; +} + +.title.is-6 { + font-size: 1rem; +} + +.title.is-7 { + font-size: 0.75rem; +} + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; +} + +.subtitle strong { + color: #363636; + font-weight: 600; +} + +.subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; +} + +.subtitle.is-1 { + font-size: 3rem; +} + +.subtitle.is-2 { + font-size: 2.5rem; +} + +.subtitle.is-3 { + font-size: 2rem; +} + +.subtitle.is-4 { + font-size: 1.5rem; +} + +.subtitle.is-5 { + font-size: 1.25rem; +} + +.subtitle.is-6 { + font-size: 1rem; +} + +.subtitle.is-7 { + font-size: 0.75rem; +} + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; +} + +.number { + align-items: center; + background-color: whitesmoke; + border-radius: 9999px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; +} + +/* Bulma Form */ +.input, .textarea, .select select { + background-color: white; + border-color: #dbdbdb; + border-radius: 4px; + color: #363636; +} + +.input::-moz-placeholder, .textarea::-moz-placeholder, .select select::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input::-webkit-input-placeholder, .textarea::-webkit-input-placeholder, .select select::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:-moz-placeholder, .textarea:-moz-placeholder, .select select:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:-ms-input-placeholder, .textarea:-ms-input-placeholder, .select select:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:hover, .textarea:hover, .select select:hover, .is-hovered.input, .is-hovered.textarea, .select select.is-hovered { + border-color: #b5b5b5; +} + +.input:focus, .textarea:focus, .select select:focus, .is-focused.input, .is-focused.textarea, .select select.is-focused, .input:active, .textarea:active, .select select:active, .is-active.input, .is-active.textarea, .select select.is-active { + border-color: #485fc7; + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.input[disabled], .textarea[disabled], .select select[disabled], +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +.select fieldset[disabled] select { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; +} + +.input[disabled]::-moz-placeholder, .textarea[disabled]::-moz-placeholder, .select select[disabled]::-moz-placeholder, +fieldset[disabled] .input::-moz-placeholder, +fieldset[disabled] .textarea::-moz-placeholder, +fieldset[disabled] .select select::-moz-placeholder, +.select fieldset[disabled] select::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]::-webkit-input-placeholder, .textarea[disabled]::-webkit-input-placeholder, .select select[disabled]::-webkit-input-placeholder, +fieldset[disabled] .input::-webkit-input-placeholder, +fieldset[disabled] .textarea::-webkit-input-placeholder, +fieldset[disabled] .select select::-webkit-input-placeholder, +.select fieldset[disabled] select::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]:-moz-placeholder, .textarea[disabled]:-moz-placeholder, .select select[disabled]:-moz-placeholder, +fieldset[disabled] .input:-moz-placeholder, +fieldset[disabled] .textarea:-moz-placeholder, +fieldset[disabled] .select select:-moz-placeholder, +.select fieldset[disabled] select:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]:-ms-input-placeholder, .textarea[disabled]:-ms-input-placeholder, .select select[disabled]:-ms-input-placeholder, +fieldset[disabled] .input:-ms-input-placeholder, +fieldset[disabled] .textarea:-ms-input-placeholder, +fieldset[disabled] .select select:-ms-input-placeholder, +.select fieldset[disabled] select:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input, .textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(10, 10, 10, 0.05); + max-width: 100%; + width: 100%; +} + +.input[readonly], .textarea[readonly] { + box-shadow: none; +} + +.is-white.input, .is-white.textarea { + border-color: white; +} + +.is-white.input:focus, .is-white.textarea:focus, .is-white.is-focused.input, .is-white.is-focused.textarea, .is-white.input:active, .is-white.textarea:active, .is-white.is-active.input, .is-white.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.is-black.input, .is-black.textarea { + border-color: #0a0a0a; +} + +.is-black.input:focus, .is-black.textarea:focus, .is-black.is-focused.input, .is-black.is-focused.textarea, .is-black.input:active, .is-black.textarea:active, .is-black.is-active.input, .is-black.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.is-light.input, .is-light.textarea { + border-color: whitesmoke; +} + +.is-light.input:focus, .is-light.textarea:focus, .is-light.is-focused.input, .is-light.is-focused.textarea, .is-light.input:active, .is-light.textarea:active, .is-light.is-active.input, .is-light.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.is-dark.input, .is-dark.textarea { + border-color: #363636; +} + +.is-dark.input:focus, .is-dark.textarea:focus, .is-dark.is-focused.input, .is-dark.is-focused.textarea, .is-dark.input:active, .is-dark.textarea:active, .is-dark.is-active.input, .is-dark.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.is-primary.input, .is-primary.textarea { + border-color: #00d1b2; +} + +.is-primary.input:focus, .is-primary.textarea:focus, .is-primary.is-focused.input, .is-primary.is-focused.textarea, .is-primary.input:active, .is-primary.textarea:active, .is-primary.is-active.input, .is-primary.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.is-link.input, .is-link.textarea { + border-color: #485fc7; +} + +.is-link.input:focus, .is-link.textarea:focus, .is-link.is-focused.input, .is-link.is-focused.textarea, .is-link.input:active, .is-link.textarea:active, .is-link.is-active.input, .is-link.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.is-info.input, .is-info.textarea { + border-color: #3e8ed0; +} + +.is-info.input:focus, .is-info.textarea:focus, .is-info.is-focused.input, .is-info.is-focused.textarea, .is-info.input:active, .is-info.textarea:active, .is-info.is-active.input, .is-info.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.is-success.input, .is-success.textarea { + border-color: #48c78e; +} + +.is-success.input:focus, .is-success.textarea:focus, .is-success.is-focused.input, .is-success.is-focused.textarea, .is-success.input:active, .is-success.textarea:active, .is-success.is-active.input, .is-success.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.is-warning.input, .is-warning.textarea { + border-color: #ffe08a; +} + +.is-warning.input:focus, .is-warning.textarea:focus, .is-warning.is-focused.input, .is-warning.is-focused.textarea, .is-warning.input:active, .is-warning.textarea:active, .is-warning.is-active.input, .is-warning.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.is-danger.input, .is-danger.textarea { + border-color: #f14668; +} + +.is-danger.input:focus, .is-danger.textarea:focus, .is-danger.is-focused.input, .is-danger.is-focused.textarea, .is-danger.input:active, .is-danger.textarea:active, .is-danger.is-active.input, .is-danger.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.is-small.input, .is-small.textarea { + border-radius: 2px; + font-size: 0.75rem; +} + +.is-medium.input, .is-medium.textarea { + font-size: 1.25rem; +} + +.is-large.input, .is-large.textarea { + font-size: 1.5rem; +} + +.is-fullwidth.input, .is-fullwidth.textarea { + display: block; + width: 100%; +} + +.is-inline.input, .is-inline.textarea { + display: inline; + width: auto; +} + +.input.is-rounded { + border-radius: 9999px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); +} + +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; +} + +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; +} + +.textarea:not([rows]) { + max-height: 40em; + min-height: 8em; +} + +.textarea[rows] { + height: initial; +} + +.textarea.has-fixed-size { + resize: none; +} + +.checkbox, .radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; +} + +.checkbox input, .radio input { + cursor: pointer; +} + +.checkbox:hover, .radio:hover { + color: #363636; +} + +.checkbox[disabled], .radio[disabled], +fieldset[disabled] .checkbox, +fieldset[disabled] .radio, +.checkbox input[disabled], +.radio input[disabled] { + color: #7a7a7a; + cursor: not-allowed; +} + +.radio + .radio { + margin-left: 0.5em; +} + +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; +} + +.select:not(.is-multiple) { + height: 2.5em; +} + +.select:not(.is-multiple):not(.is-loading)::after { + border-color: #485fc7; + right: 1.125em; + z-index: 4; +} + +.select.is-rounded select { + border-radius: 9999px; + padding-left: 1em; +} + +.select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; +} + +.select select::-ms-expand { + display: none; +} + +.select select[disabled]:hover, +fieldset[disabled] .select select:hover { + border-color: whitesmoke; +} + +.select select:not([multiple]) { + padding-right: 2.5em; +} + +.select select[multiple] { + height: auto; + padding: 0; +} + +.select select[multiple] option { + padding: 0.5em 1em; +} + +.select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; +} + +.select.is-white:not(:hover)::after { + border-color: white; +} + +.select.is-white select { + border-color: white; +} + +.select.is-white select:hover, .select.is-white select.is-hovered { + border-color: #f2f2f2; +} + +.select.is-white select:focus, .select.is-white select.is-focused, .select.is-white select:active, .select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.select.is-black:not(:hover)::after { + border-color: #0a0a0a; +} + +.select.is-black select { + border-color: #0a0a0a; +} + +.select.is-black select:hover, .select.is-black select.is-hovered { + border-color: black; +} + +.select.is-black select:focus, .select.is-black select.is-focused, .select.is-black select:active, .select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.select.is-light:not(:hover)::after { + border-color: whitesmoke; +} + +.select.is-light select { + border-color: whitesmoke; +} + +.select.is-light select:hover, .select.is-light select.is-hovered { + border-color: #e8e8e8; +} + +.select.is-light select:focus, .select.is-light select.is-focused, .select.is-light select:active, .select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.select.is-dark:not(:hover)::after { + border-color: #363636; +} + +.select.is-dark select { + border-color: #363636; +} + +.select.is-dark select:hover, .select.is-dark select.is-hovered { + border-color: #292929; +} + +.select.is-dark select:focus, .select.is-dark select.is-focused, .select.is-dark select:active, .select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.select.is-primary:not(:hover)::after { + border-color: #00d1b2; +} + +.select.is-primary select { + border-color: #00d1b2; +} + +.select.is-primary select:hover, .select.is-primary select.is-hovered { + border-color: #00b89c; +} + +.select.is-primary select:focus, .select.is-primary select.is-focused, .select.is-primary select:active, .select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.select.is-link:not(:hover)::after { + border-color: #485fc7; +} + +.select.is-link select { + border-color: #485fc7; +} + +.select.is-link select:hover, .select.is-link select.is-hovered { + border-color: #3a51bb; +} + +.select.is-link select:focus, .select.is-link select.is-focused, .select.is-link select:active, .select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.select.is-info:not(:hover)::after { + border-color: #3e8ed0; +} + +.select.is-info select { + border-color: #3e8ed0; +} + +.select.is-info select:hover, .select.is-info select.is-hovered { + border-color: #3082c5; +} + +.select.is-info select:focus, .select.is-info select.is-focused, .select.is-info select:active, .select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.select.is-success:not(:hover)::after { + border-color: #48c78e; +} + +.select.is-success select { + border-color: #48c78e; +} + +.select.is-success select:hover, .select.is-success select.is-hovered { + border-color: #3abb81; +} + +.select.is-success select:focus, .select.is-success select.is-focused, .select.is-success select:active, .select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.select.is-warning:not(:hover)::after { + border-color: #ffe08a; +} + +.select.is-warning select { + border-color: #ffe08a; +} + +.select.is-warning select:hover, .select.is-warning select.is-hovered { + border-color: #ffd970; +} + +.select.is-warning select:focus, .select.is-warning select.is-focused, .select.is-warning select:active, .select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.select.is-danger:not(:hover)::after { + border-color: #f14668; +} + +.select.is-danger select { + border-color: #f14668; +} + +.select.is-danger select:hover, .select.is-danger select.is-hovered { + border-color: #ef2e55; +} + +.select.is-danger select:focus, .select.is-danger select.is-focused, .select.is-danger select:active, .select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.select.is-small { + border-radius: 2px; + font-size: 0.75rem; +} + +.select.is-medium { + font-size: 1.25rem; +} + +.select.is-large { + font-size: 1.5rem; +} + +.select.is-disabled::after { + border-color: #7a7a7a !important; + opacity: 0.5; +} + +.select.is-fullwidth { + width: 100%; +} + +.select.is-fullwidth select { + width: 100%; +} + +.select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; +} + +.select.is-loading.is-small:after { + font-size: 0.75rem; +} + +.select.is-loading.is-medium:after { + font-size: 1.25rem; +} + +.select.is-loading.is-large:after { + font-size: 1.5rem; +} + +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; +} + +.file.is-white .file-cta { + background-color: white; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-white:hover .file-cta, .file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-white:focus .file-cta, .file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.25); + color: #0a0a0a; +} + +.file.is-white:active .file-cta, .file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: white; +} + +.file.is-black:hover .file-cta, .file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: white; +} + +.file.is-black:focus .file-cta, .file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10, 10, 10, 0.25); + color: white; +} + +.file.is-black:active .file-cta, .file.is-black.is-active .file-cta { + background-color: black; + border-color: transparent; + color: white; +} + +.file.is-light .file-cta { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:hover .file-cta, .file.is-light.is-hovered .file-cta { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:focus .file-cta, .file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245, 245, 245, 0.25); + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:active .file-cta, .file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; +} + +.file.is-dark:hover .file-cta, .file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} + +.file.is-dark:focus .file-cta, .file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54, 54, 54, 0.25); + color: #fff; +} + +.file.is-dark:active .file-cta, .file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; +} + +.file.is-primary .file-cta { + background-color: #00d1b2; + border-color: transparent; + color: #fff; +} + +.file.is-primary:hover .file-cta, .file.is-primary.is-hovered .file-cta { + background-color: #00c4a7; + border-color: transparent; + color: #fff; +} + +.file.is-primary:focus .file-cta, .file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0, 209, 178, 0.25); + color: #fff; +} + +.file.is-primary:active .file-cta, .file.is-primary.is-active .file-cta { + background-color: #00b89c; + border-color: transparent; + color: #fff; +} + +.file.is-link .file-cta { + background-color: #485fc7; + border-color: transparent; + color: #fff; +} + +.file.is-link:hover .file-cta, .file.is-link.is-hovered .file-cta { + background-color: #3e56c4; + border-color: transparent; + color: #fff; +} + +.file.is-link:focus .file-cta, .file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 95, 199, 0.25); + color: #fff; +} + +.file.is-link:active .file-cta, .file.is-link.is-active .file-cta { + background-color: #3a51bb; + border-color: transparent; + color: #fff; +} + +.file.is-info .file-cta { + background-color: #3e8ed0; + border-color: transparent; + color: #fff; +} + +.file.is-info:hover .file-cta, .file.is-info.is-hovered .file-cta { + background-color: #3488ce; + border-color: transparent; + color: #fff; +} + +.file.is-info:focus .file-cta, .file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(62, 142, 208, 0.25); + color: #fff; +} + +.file.is-info:active .file-cta, .file.is-info.is-active .file-cta { + background-color: #3082c5; + border-color: transparent; + color: #fff; +} + +.file.is-success .file-cta { + background-color: #48c78e; + border-color: transparent; + color: #fff; +} + +.file.is-success:hover .file-cta, .file.is-success.is-hovered .file-cta { + background-color: #3ec487; + border-color: transparent; + color: #fff; +} + +.file.is-success:focus .file-cta, .file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 199, 142, 0.25); + color: #fff; +} + +.file.is-success:active .file-cta, .file.is-success.is-active .file-cta { + background-color: #3abb81; + border-color: transparent; + color: #fff; +} + +.file.is-warning .file-cta { + background-color: #ffe08a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:hover .file-cta, .file.is-warning.is-hovered .file-cta { + background-color: #ffdc7d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:focus .file-cta, .file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 224, 138, 0.25); + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:active .file-cta, .file.is-warning.is-active .file-cta { + background-color: #ffd970; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-danger .file-cta { + background-color: #f14668; + border-color: transparent; + color: #fff; +} + +.file.is-danger:hover .file-cta, .file.is-danger.is-hovered .file-cta { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} + +.file.is-danger:focus .file-cta, .file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(241, 70, 104, 0.25); + color: #fff; +} + +.file.is-danger:active .file-cta, .file.is-danger.is-active .file-cta { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} + +.file.is-small { + font-size: 0.75rem; +} + +.file.is-normal { + font-size: 1rem; +} + +.file.is-medium { + font-size: 1.25rem; +} + +.file.is-medium .file-icon .fa { + font-size: 21px; +} + +.file.is-large { + font-size: 1.5rem; +} + +.file.is-large .file-icon .fa { + font-size: 28px; +} + +.file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.file.has-name.is-empty .file-cta { + border-radius: 4px; +} + +.file.has-name.is-empty .file-name { + display: none; +} + +.file.is-boxed .file-label { + flex-direction: column; +} + +.file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; +} + +.file.is-boxed .file-name { + border-width: 0 1px 1px; +} + +.file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; +} + +.file.is-boxed .file-icon .fa { + font-size: 21px; +} + +.file.is-boxed.is-small .file-icon .fa { + font-size: 14px; +} + +.file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; +} + +.file.is-boxed.is-large .file-icon .fa { + font-size: 35px; +} + +.file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; +} + +.file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; +} + +.file.is-centered { + justify-content: center; +} + +.file.is-fullwidth .file-label { + width: 100%; +} + +.file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; +} + +.file.is-right { + justify-content: flex-end; +} + +.file.is-right .file-cta { + border-radius: 0 4px 4px 0; +} + +.file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; +} + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; +} + +.file-label:hover .file-cta { + background-color: #eeeeee; + color: #363636; +} + +.file-label:hover .file-name { + border-color: #d5d5d5; +} + +.file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; +} + +.file-label:active .file-name { + border-color: #cfcfcf; +} + +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; +} + +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; +} + +.file-cta { + background-color: whitesmoke; + color: #4a4a4a; +} + +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: inherit; + text-overflow: ellipsis; +} + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; +} + +.file-icon .fa { + font-size: 14px; +} + +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; +} + +.label:not(:last-child) { + margin-bottom: 0.5em; +} + +.label.is-small { + font-size: 0.75rem; +} + +.label.is-medium { + font-size: 1.25rem; +} + +.label.is-large { + font-size: 1.5rem; +} + +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; +} + +.help.is-white { + color: white; +} + +.help.is-black { + color: #0a0a0a; +} + +.help.is-light { + color: whitesmoke; +} + +.help.is-dark { + color: #363636; +} + +.help.is-primary { + color: #00d1b2; +} + +.help.is-link { + color: #485fc7; +} + +.help.is-info { + color: #3e8ed0; +} + +.help.is-success { + color: #48c78e; +} + +.help.is-warning { + color: #ffe08a; +} + +.help.is-danger { + color: #f14668; +} + +.field:not(:last-child) { + margin-bottom: 0.75rem; +} + +.field.has-addons { + display: flex; + justify-content: flex-start; +} + +.field.has-addons .control:not(:last-child) { + margin-right: -1px; +} + +.field.has-addons .control:not(:first-child):not(:last-child) .button, +.field.has-addons .control:not(:first-child):not(:last-child) .input, +.field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; +} + +.field.has-addons .control:first-child:not(:only-child) .button, +.field.has-addons .control:first-child:not(:only-child) .input, +.field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.field.has-addons .control:last-child:not(:only-child) .button, +.field.has-addons .control:last-child:not(:only-child) .input, +.field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, +.field.has-addons .control .input:not([disabled]):hover, +.field.has-addons .control .input:not([disabled]).is-hovered, +.field.has-addons .control .select select:not([disabled]):hover, +.field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; +} + +.field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, +.field.has-addons .control .input:not([disabled]):focus, +.field.has-addons .control .input:not([disabled]).is-focused, +.field.has-addons .control .input:not([disabled]):active, +.field.has-addons .control .input:not([disabled]).is-active, +.field.has-addons .control .select select:not([disabled]):focus, +.field.has-addons .control .select select:not([disabled]).is-focused, +.field.has-addons .control .select select:not([disabled]):active, +.field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; +} + +.field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, +.field.has-addons .control .input:not([disabled]):focus:hover, +.field.has-addons .control .input:not([disabled]).is-focused:hover, +.field.has-addons .control .input:not([disabled]):active:hover, +.field.has-addons .control .input:not([disabled]).is-active:hover, +.field.has-addons .control .select select:not([disabled]):focus:hover, +.field.has-addons .control .select select:not([disabled]).is-focused:hover, +.field.has-addons .control .select select:not([disabled]):active:hover, +.field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; +} + +.field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.field.has-addons.has-addons-centered { + justify-content: center; +} + +.field.has-addons.has-addons-right { + justify-content: flex-end; +} + +.field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; +} + +.field.is-grouped { + display: flex; + justify-content: flex-start; +} + +.field.is-grouped > .control { + flex-shrink: 0; +} + +.field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} + +.field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.field.is-grouped.is-grouped-centered { + justify-content: center; +} + +.field.is-grouped.is-grouped-right { + justify-content: flex-end; +} + +.field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; +} + +.field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; +} + +.field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; +} + +.field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; + } +} + +.field-label .label { + font-size: inherit; +} + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} + +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; + } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; + } +} + +.field-body .field .field { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body > .field { + flex-shrink: 1; + } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; + } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; + } +} + +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: inherit; +} + +.control.has-icons-left .input:focus ~ .icon, +.control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, +.control.has-icons-right .select:focus ~ .icon { + color: #4a4a4a; +} + +.control.has-icons-left .input.is-small ~ .icon, +.control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, +.control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; +} + +.control.has-icons-left .input.is-medium ~ .icon, +.control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, +.control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; +} + +.control.has-icons-left .input.is-large ~ .icon, +.control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, +.control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; +} + +.control.has-icons-left .icon, .control.has-icons-right .icon { + color: #dbdbdb; + height: 2.5em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.5em; + z-index: 4; +} + +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: 2.5em; +} + +.control.has-icons-left .icon.is-left { + left: 0; +} + +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: 2.5em; +} + +.control.has-icons-right .icon.is-right { + right: 0; +} + +.control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; +} + +.control.is-loading.is-small:after { + font-size: 0.75rem; +} + +.control.is-loading.is-medium:after { + font-size: 1.25rem; +} + +.control.is-loading.is-large:after { + font-size: 1.5rem; +} + +/* Bulma Components */ +.breadcrumb { + font-size: 1rem; + white-space: nowrap; +} + +.breadcrumb a { + align-items: center; + color: #485fc7; + display: flex; + justify-content: center; + padding: 0 0.75em; +} + +.breadcrumb a:hover { + color: #363636; +} + +.breadcrumb li { + align-items: center; + display: flex; +} + +.breadcrumb li:first-child a { + padding-left: 0; +} + +.breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; +} + +.breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; +} + +.breadcrumb ul, +.breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.breadcrumb .icon:first-child { + margin-right: 0.5em; +} + +.breadcrumb .icon:last-child { + margin-left: 0.5em; +} + +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + justify-content: center; +} + +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + justify-content: flex-end; +} + +.breadcrumb.is-small { + font-size: 0.75rem; +} + +.breadcrumb.is-medium { + font-size: 1.25rem; +} + +.breadcrumb.is-large { + font-size: 1.5rem; +} + +.breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; +} + +.breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; +} + +.breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; +} + +.breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; +} + +.card { + background-color: white; + border-radius: 0.25rem; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + max-width: 100%; + position: relative; +} + +.card-header:first-child, .card-content:first-child, .card-footer:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-header:last-child, .card-content:last-child, .card-footer:last-child { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(10, 10, 10, 0.1); + display: flex; +} + +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; +} + +.card-header-title.is-centered { + justify-content: center; +} + +.card-header-icon { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + color: currentColor; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; +} + +.card-image { + display: block; + position: relative; +} + +.card-image:first-child img { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-image:last-child img { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.card-content { + background-color: transparent; + padding: 1.5rem; +} + +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; +} + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; +} + +.card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; +} + +.card .media:not(:last-child) { + margin-bottom: 1.5rem; +} + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; +} + +.dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} + +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} + +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; +} + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; +} + +.dropdown-content { + background-color: white; + border-radius: 4px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; +} + +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: inherit; + white-space: nowrap; + width: 100%; +} + +a.dropdown-item:hover, +button.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; +} + +a.dropdown-item.is-active, +button.dropdown-item.is-active { + background-color: #485fc7; + color: #fff; +} + +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} + +.level { + align-items: center; + justify-content: space-between; +} + +.level code { + border-radius: 4px; +} + +.level img { + display: inline-block; + vertical-align: top; +} + +.level.is-mobile { + display: flex; +} + +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: flex; +} + +.level.is-mobile .level-left + .level-right { + margin-top: 0; +} + +.level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} + +.level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; +} + +@media screen and (min-width: 769px), print { + .level { + display: flex; + } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; + } +} + +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; +} + +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} + +@media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} + +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + flex-grow: 1; +} + +@media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; + } +} + +.level-left { + align-items: center; + justify-content: flex-start; +} + +@media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; + } +} + +@media screen and (min-width: 769px), print { + .level-left { + display: flex; + } +} + +.level-right { + align-items: center; + justify-content: flex-end; +} + +@media screen and (min-width: 769px), print { + .level-right { + display: flex; + } +} + +.media { + align-items: flex-start; + display: flex; + text-align: inherit; +} + +.media .content:not(:last-child) { + margin-bottom: 0.75rem; +} + +.media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: flex; + padding-top: 0.75rem; +} + +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: 0.5rem; +} + +.media .media .media { + padding-top: 0.5rem; +} + +.media .media .media + .media { + margin-top: 0.5rem; +} + +.media + .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; +} + +.media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; +} + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} + +.media-left { + margin-right: 1rem; +} + +.media-right { + margin-left: 1rem; +} + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: inherit; +} + +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; + } +} + +.menu { + font-size: 1rem; +} + +.menu.is-small { + font-size: 0.75rem; +} + +.menu.is-medium { + font-size: 1.25rem; +} + +.menu.is-large { + font-size: 1.5rem; +} + +.menu-list { + line-height: 1.25; +} + +.menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; +} + +.menu-list a:hover { + background-color: whitesmoke; + color: #363636; +} + +.menu-list a.is-active { + background-color: #485fc7; + color: #fff; +} + +.menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; +} + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.menu-label:not(:first-child) { + margin-top: 1em; +} + +.menu-label:not(:last-child) { + margin-bottom: 1em; +} + +.message { + background-color: whitesmoke; + border-radius: 4px; + font-size: 1rem; +} + +.message strong { + color: currentColor; +} + +.message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} + +.message.is-small { + font-size: 0.75rem; +} + +.message.is-medium { + font-size: 1.25rem; +} + +.message.is-large { + font-size: 1.5rem; +} + +.message.is-white { + background-color: white; +} + +.message.is-white .message-header { + background-color: white; + color: #0a0a0a; +} + +.message.is-white .message-body { + border-color: white; +} + +.message.is-black { + background-color: #fafafa; +} + +.message.is-black .message-header { + background-color: #0a0a0a; + color: white; +} + +.message.is-black .message-body { + border-color: #0a0a0a; +} + +.message.is-light { + background-color: #fafafa; +} + +.message.is-light .message-header { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.message.is-light .message-body { + border-color: whitesmoke; +} + +.message.is-dark { + background-color: #fafafa; +} + +.message.is-dark .message-header { + background-color: #363636; + color: #fff; +} + +.message.is-dark .message-body { + border-color: #363636; +} + +.message.is-primary { + background-color: #ebfffc; +} + +.message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; +} + +.message.is-primary .message-body { + border-color: #00d1b2; + color: #00947e; +} + +.message.is-link { + background-color: #eff1fa; +} + +.message.is-link .message-header { + background-color: #485fc7; + color: #fff; +} + +.message.is-link .message-body { + border-color: #485fc7; + color: #3850b7; +} + +.message.is-info { + background-color: #eff5fb; +} + +.message.is-info .message-header { + background-color: #3e8ed0; + color: #fff; +} + +.message.is-info .message-body { + border-color: #3e8ed0; + color: #296fa8; +} + +.message.is-success { + background-color: #effaf5; +} + +.message.is-success .message-header { + background-color: #48c78e; + color: #fff; +} + +.message.is-success .message-body { + border-color: #48c78e; + color: #257953; +} + +.message.is-warning { + background-color: #fffaeb; +} + +.message.is-warning .message-header { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.message.is-warning .message-body { + border-color: #ffe08a; + color: #946c00; +} + +.message.is-danger { + background-color: #feecf0; +} + +.message.is-danger .message-header { + background-color: #f14668; + color: #fff; +} + +.message.is-danger .message-body { + border-color: #f14668; + color: #cc0f35; +} + +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; +} + +.message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; +} + +.message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; +} + +.message-body code, +.message-body pre { + background-color: white; +} + +.message-body pre code { + background-color: transparent; +} + +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; +} + +.modal.is-active { + display: flex; +} + +.modal-background { + background-color: rgba(10, 10, 10, 0.86); +} + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; +} + +@media screen and (min-width: 769px) { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; + } +} + +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; +} + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; +} + +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: whitesmoke; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; +} + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; +} + +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; +} + +.modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; +} + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; +} + +.navbar { + background-color: white; + min-height: 3.25rem; + position: relative; + z-index: 30; +} + +.navbar.is-white { + background-color: white; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand > .navbar-item, +.navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand > a.navbar-item:focus, .navbar.is-white .navbar-brand > a.navbar-item:hover, .navbar.is-white .navbar-brand > a.navbar-item.is-active, +.navbar.is-white .navbar-brand .navbar-link:focus, +.navbar.is-white .navbar-brand .navbar-link:hover, +.navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; +} + +.navbar.is-white .navbar-burger { + color: #0a0a0a; +} + +@media screen and (min-width: 1024px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; + } + .navbar.is-white .navbar-start > a.navbar-item:focus, .navbar.is-white .navbar-start > a.navbar-item:hover, .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; + } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; + } +} + +.navbar.is-black { + background-color: #0a0a0a; + color: white; +} + +.navbar.is-black .navbar-brand > .navbar-item, +.navbar.is-black .navbar-brand .navbar-link { + color: white; +} + +.navbar.is-black .navbar-brand > a.navbar-item:focus, .navbar.is-black .navbar-brand > a.navbar-item:hover, .navbar.is-black .navbar-brand > a.navbar-item.is-active, +.navbar.is-black .navbar-brand .navbar-link:focus, +.navbar.is-black .navbar-brand .navbar-link:hover, +.navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; +} + +.navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; +} + +.navbar.is-black .navbar-burger { + color: white; +} + +@media screen and (min-width: 1024px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; + } + .navbar.is-black .navbar-start > a.navbar-item:focus, .navbar.is-black .navbar-start > a.navbar-item:hover, .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; + } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; + } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; + } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; + } +} + +.navbar.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand > .navbar-item, +.navbar.is-light .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand > a.navbar-item:focus, .navbar.is-light .navbar-brand > a.navbar-item:hover, .navbar.is-light .navbar-brand > a.navbar-item.is-active, +.navbar.is-light .navbar-brand .navbar-link:focus, +.navbar.is-light .navbar-brand .navbar-link:hover, +.navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-burger { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (min-width: 1024px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-start > a.navbar-item:focus, .navbar.is-light .navbar-start > a.navbar-item:hover, .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); + } +} + +.navbar.is-dark { + background-color: #363636; + color: #fff; +} + +.navbar.is-dark .navbar-brand > .navbar-item, +.navbar.is-dark .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-dark .navbar-brand > a.navbar-item:focus, .navbar.is-dark .navbar-brand > a.navbar-item:hover, .navbar.is-dark .navbar-brand > a.navbar-item.is-active, +.navbar.is-dark .navbar-brand .navbar-link:focus, +.navbar.is-dark .navbar-brand .navbar-link:hover, +.navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; +} + +.navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-dark .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-dark .navbar-start > a.navbar-item:focus, .navbar.is-dark .navbar-start > a.navbar-item:hover, .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; + } +} + +.navbar.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.navbar.is-primary .navbar-brand > .navbar-item, +.navbar.is-primary .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-primary .navbar-brand > a.navbar-item:focus, .navbar.is-primary .navbar-brand > a.navbar-item:hover, .navbar.is-primary .navbar-brand > a.navbar-item.is-active, +.navbar.is-primary .navbar-brand .navbar-link:focus, +.navbar.is-primary .navbar-brand .navbar-link:hover, +.navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-primary .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-primary .navbar-start > a.navbar-item:focus, .navbar.is-primary .navbar-start > a.navbar-item:hover, .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; + } +} + +.navbar.is-link { + background-color: #485fc7; + color: #fff; +} + +.navbar.is-link .navbar-brand > .navbar-item, +.navbar.is-link .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-link .navbar-brand > a.navbar-item:focus, .navbar.is-link .navbar-brand > a.navbar-item:hover, .navbar.is-link .navbar-brand > a.navbar-item.is-active, +.navbar.is-link .navbar-brand .navbar-link:focus, +.navbar.is-link .navbar-brand .navbar-link:hover, +.navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; +} + +.navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-link .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-link .navbar-start > a.navbar-item:focus, .navbar.is-link .navbar-start > a.navbar-item:hover, .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; + } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3a51bb; + color: #fff; + } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #485fc7; + color: #fff; + } +} + +.navbar.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.navbar.is-info .navbar-brand > .navbar-item, +.navbar.is-info .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-info .navbar-brand > a.navbar-item:focus, .navbar.is-info .navbar-brand > a.navbar-item:hover, .navbar.is-info .navbar-brand > a.navbar-item.is-active, +.navbar.is-info .navbar-brand .navbar-link:focus, +.navbar.is-info .navbar-brand .navbar-link:hover, +.navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #3082c5; + color: #fff; +} + +.navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-info .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-info .navbar-start > a.navbar-item:focus, .navbar.is-info .navbar-start > a.navbar-item:hover, .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #3082c5; + color: #fff; + } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3082c5; + color: #fff; + } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #3e8ed0; + color: #fff; + } +} + +.navbar.is-success { + background-color: #48c78e; + color: #fff; +} + +.navbar.is-success .navbar-brand > .navbar-item, +.navbar.is-success .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-success .navbar-brand > a.navbar-item:focus, .navbar.is-success .navbar-brand > a.navbar-item:hover, .navbar.is-success .navbar-brand > a.navbar-item.is-active, +.navbar.is-success .navbar-brand .navbar-link:focus, +.navbar.is-success .navbar-brand .navbar-link:hover, +.navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #3abb81; + color: #fff; +} + +.navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-success .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-success .navbar-start > a.navbar-item:focus, .navbar.is-success .navbar-start > a.navbar-item:hover, .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #3abb81; + color: #fff; + } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3abb81; + color: #fff; + } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #48c78e; + color: #fff; + } +} + +.navbar.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand > .navbar-item, +.navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand > a.navbar-item:focus, .navbar.is-warning .navbar-brand > a.navbar-item:hover, .navbar.is-warning .navbar-brand > a.navbar-item.is-active, +.navbar.is-warning .navbar-brand .navbar-link:focus, +.navbar.is-warning .navbar-brand .navbar-link:hover, +.navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-burger { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (min-width: 1024px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start > a.navbar-item:focus, .navbar.is-warning .navbar-start > a.navbar-item:hover, .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); + } +} + +.navbar.is-danger { + background-color: #f14668; + color: #fff; +} + +.navbar.is-danger .navbar-brand > .navbar-item, +.navbar.is-danger .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-danger .navbar-brand > a.navbar-item:focus, .navbar.is-danger .navbar-brand > a.navbar-item:hover, .navbar.is-danger .navbar-brand > a.navbar-item.is-active, +.navbar.is-danger .navbar-brand .navbar-link:focus, +.navbar.is-danger .navbar-brand .navbar-link:hover, +.navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} + +.navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-danger .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-danger .navbar-start > a.navbar-item:focus, .navbar.is-danger .navbar-start > a.navbar-item:hover, .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #f14668; + color: #fff; + } +} + +.navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; +} + +.navbar.has-shadow { + box-shadow: 0 2px 0 0 whitesmoke; +} + +.navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; +} + +.navbar.is-fixed-bottom { + bottom: 0; +} + +.navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 whitesmoke; +} + +.navbar.is-fixed-top { + top: 0; +} + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; +} + +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; +} + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; +} + +.navbar-brand a.navbar-item:focus, .navbar-brand a.navbar-item:hover { + background-color: transparent; +} + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} + +.navbar-burger { + color: #4a4a4a; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; +} + +.navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; +} + +.navbar-burger span:nth-child(1) { + top: calc(50% - 6px); +} + +.navbar-burger span:nth-child(2) { + top: calc(50% - 1px); +} + +.navbar-burger span:nth-child(3) { + top: calc(50% + 4px); +} + +.navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); +} + +.navbar-burger.is-active span:nth-child(2) { + opacity: 0; +} + +.navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); +} + +.navbar-menu { + display: none; +} + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; +} + +.navbar-item .icon:only-child, +.navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; +} + +a.navbar-item, +.navbar-link { + cursor: pointer; +} + +a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, a.navbar-item.is-active, +.navbar-link:focus, +.navbar-link:focus-within, +.navbar-link:hover, +.navbar-link.is-active { + background-color: #fafafa; + color: #485fc7; +} + +.navbar-item { + flex-grow: 0; + flex-shrink: 0; +} + +.navbar-item img { + max-height: 1.75rem; +} + +.navbar-item.has-dropdown { + padding: 0; +} + +.navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); +} + +.navbar-item.is-tab:focus, .navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #485fc7; +} + +.navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #485fc7; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #485fc7; + padding-bottom: calc(0.5rem - 3px); +} + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; +} + +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; +} + +.navbar-link:not(.is-arrowless)::after { + border-color: #485fc7; + margin-top: -0.375em; + right: 1.125em; +} + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.navbar-divider { + background-color: whitesmoke; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; +} + +@media screen and (max-width: 1023px) { + .navbar > .container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; + } + .navbar-link::after { + display: none; + } + .navbar-menu { + background-color: white; + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; + } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; + } +} + +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; + } + .navbar { + min-height: 3.25rem; + } + .navbar.is-spaced { + padding: 1rem 2rem; + } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; + } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; + } + .navbar.is-transparent a.navbar-item:focus, .navbar.is-transparent a.navbar-item:hover, .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #485fc7; + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; + } + .navbar-item.has-dropdown { + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + } + .navbar-start { + justify-content: flex-start; + margin-right: auto; + } + .navbar-end { + justify-content: flex-end; + margin-left: auto; + } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; + } + .navbar-dropdown a.navbar-item:focus, .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #485fc7; + } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -0.75rem; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -0.75rem; + } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; + } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; + } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; + } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #0a0a0a; + } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; + } + .navbar-item.has-dropdown:focus .navbar-link, .navbar-item.has-dropdown:hover .navbar-link, .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; + } +} + +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); +} + +.pagination { + font-size: 1rem; + margin: -0.25rem; +} + +.pagination.is-small { + font-size: 0.75rem; +} + +.pagination.is-medium { + font-size: 1.25rem; +} + +.pagination.is-large { + font-size: 1.5rem; +} + +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 9999px; +} + +.pagination.is-rounded .pagination-link { + border-radius: 9999px; +} + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.5em; +} + +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + border-color: #b5b5b5; + color: #363636; +} + +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + border-color: #485fc7; +} + +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); +} + +.pagination-previous[disabled], .pagination-previous.is-disabled, +.pagination-next[disabled], +.pagination-next.is-disabled, +.pagination-link[disabled], +.pagination-link.is-disabled { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; +} + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.pagination-link.is-current { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; +} + +.pagination-list { + flex-wrap: wrap; +} + +.pagination-list li { + list-style: none; +} + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; + } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; + } +} + +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; + } + .pagination-previous, + .pagination-next, + .pagination-link, + .pagination-ellipsis { + margin-bottom: 0; + margin-top: 0; + } + .pagination-previous { + order: 2; + } + .pagination-next { + order: 3; + } + .pagination { + justify-content: space-between; + margin-bottom: 0; + margin-top: 0; + } + .pagination.is-centered .pagination-previous { + order: 1; + } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; + } + .pagination.is-centered .pagination-next { + order: 3; + } + .pagination.is-right .pagination-previous { + order: 1; + } + .pagination.is-right .pagination-next { + order: 2; + } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; + } +} + +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + font-size: 1rem; +} + +.panel:not(:last-child) { + margin-bottom: 1.5rem; +} + +.panel.is-white .panel-heading { + background-color: white; + color: #0a0a0a; +} + +.panel.is-white .panel-tabs a.is-active { + border-bottom-color: white; +} + +.panel.is-white .panel-block.is-active .panel-icon { + color: white; +} + +.panel.is-black .panel-heading { + background-color: #0a0a0a; + color: white; +} + +.panel.is-black .panel-tabs a.is-active { + border-bottom-color: #0a0a0a; +} + +.panel.is-black .panel-block.is-active .panel-icon { + color: #0a0a0a; +} + +.panel.is-light .panel-heading { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.panel.is-light .panel-tabs a.is-active { + border-bottom-color: whitesmoke; +} + +.panel.is-light .panel-block.is-active .panel-icon { + color: whitesmoke; +} + +.panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; +} + +.panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; +} + +.panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; +} + +.panel.is-primary .panel-heading { + background-color: #00d1b2; + color: #fff; +} + +.panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #00d1b2; +} + +.panel.is-primary .panel-block.is-active .panel-icon { + color: #00d1b2; +} + +.panel.is-link .panel-heading { + background-color: #485fc7; + color: #fff; +} + +.panel.is-link .panel-tabs a.is-active { + border-bottom-color: #485fc7; +} + +.panel.is-link .panel-block.is-active .panel-icon { + color: #485fc7; +} + +.panel.is-info .panel-heading { + background-color: #3e8ed0; + color: #fff; +} + +.panel.is-info .panel-tabs a.is-active { + border-bottom-color: #3e8ed0; +} + +.panel.is-info .panel-block.is-active .panel-icon { + color: #3e8ed0; +} + +.panel.is-success .panel-heading { + background-color: #48c78e; + color: #fff; +} + +.panel.is-success .panel-tabs a.is-active { + border-bottom-color: #48c78e; +} + +.panel.is-success .panel-block.is-active .panel-icon { + color: #48c78e; +} + +.panel.is-warning .panel-heading { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ffe08a; +} + +.panel.is-warning .panel-block.is-active .panel-icon { + color: #ffe08a; +} + +.panel.is-danger .panel-heading { + background-color: #f14668; + color: #fff; +} + +.panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #f14668; +} + +.panel.is-danger .panel-block.is-active .panel-icon { + color: #f14668; +} + +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; +} + +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; +} + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; +} + +.panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; +} + +.panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; +} + +.panel-list a { + color: #4a4a4a; +} + +.panel-list a:hover { + color: #485fc7; +} + +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; +} + +.panel-block input[type="checkbox"] { + margin-right: 0.75em; +} + +.panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; +} + +.panel-block.is-wrapped { + flex-wrap: wrap; +} + +.panel-block.is-active { + border-left-color: #485fc7; + color: #363636; +} + +.panel-block.is-active .panel-icon { + color: #485fc7; +} + +.panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} + +a.panel-block, +label.panel-block { + cursor: pointer; +} + +a.panel-block:hover, +label.panel-block:hover { + background-color: whitesmoke; +} + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; +} + +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} + +.tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; +} + +.tabs a:hover { + border-bottom-color: #363636; + color: #363636; +} + +.tabs li { + display: block; +} + +.tabs li.is-active a { + border-bottom-color: #485fc7; + color: #485fc7; +} + +.tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; +} + +.tabs ul.is-left { + padding-right: 0.75em; +} + +.tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} + +.tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; +} + +.tabs .icon:first-child { + margin-right: 0.5em; +} + +.tabs .icon:last-child { + margin-left: 0.5em; +} + +.tabs.is-centered ul { + justify-content: center; +} + +.tabs.is-right ul { + justify-content: flex-end; +} + +.tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} + +.tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; +} + +.tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; +} + +.tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; +} + +.tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; +} + +.tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; +} + +.tabs.is-toggle li + li { + margin-left: -1px; +} + +.tabs.is-toggle li:first-child a { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.tabs.is-toggle li:last-child a { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.tabs.is-toggle li.is-active a { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; + z-index: 1; +} + +.tabs.is-toggle ul { + border-bottom: none; +} + +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 9999px; + border-top-left-radius: 9999px; + padding-left: 1.25em; +} + +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 9999px; + border-top-right-radius: 9999px; + padding-right: 1.25em; +} + +.tabs.is-small { + font-size: 0.75rem; +} + +.tabs.is-medium { + font-size: 1.25rem; +} + +.tabs.is-large { + font-size: 1.5rem; +} + +/* Bulma Grid */ +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; +} + +.columns.is-mobile > .column.is-narrow { + flex: none; + width: unset; +} + +.columns.is-mobile > .column.is-full { + flex: none; + width: 100%; +} + +.columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; +} + +.columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; +} + +.columns.is-mobile > .column.is-half { + flex: none; + width: 50%; +} + +.columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; +} + +.columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; +} + +.columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; +} + +.columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; +} + +.columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; +} + +.columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; +} + +.columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; +} + +.columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; +} + +.columns.is-mobile > .column.is-offset-half { + margin-left: 50%; +} + +.columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; +} + +.columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; +} + +.columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; +} + +.columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; +} + +.columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; +} + +.columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; +} + +.columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; +} + +.columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; +} + +.columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; +} + +.columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; +} + +.columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; +} + +.columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; +} + +.columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; +} + +.columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; +} + +.columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; +} + +.columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; +} + +.columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; +} + +.columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; +} + +.columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; +} + +.columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; +} + +.columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; +} + +.columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; +} + +.columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; +} + +.columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; +} + +.columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; +} + +.columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; +} + +.columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; +} + +.columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; +} + +.columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; +} + +.columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; +} + +.columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; +} + +.columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; +} + +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + width: unset; + } + .column.is-full-mobile { + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; + } + .column.is-offset-half-mobile { + margin-left: 50%; + } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; + } + .column.is-0-mobile { + flex: none; + width: 0%; + } + .column.is-offset-0-mobile { + margin-left: 0%; + } + .column.is-1-mobile { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-mobile { + margin-left: 8.33333%; + } + .column.is-2-mobile { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-mobile { + margin-left: 16.66667%; + } + .column.is-3-mobile { + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-left: 25%; + } + .column.is-4-mobile { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-mobile { + margin-left: 33.33333%; + } + .column.is-5-mobile { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-mobile { + margin-left: 41.66667%; + } + .column.is-6-mobile { + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-left: 50%; + } + .column.is-7-mobile { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-mobile { + margin-left: 58.33333%; + } + .column.is-8-mobile { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-mobile { + margin-left: 66.66667%; + } + .column.is-9-mobile { + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-left: 75%; + } + .column.is-10-mobile { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-mobile { + margin-left: 83.33333%; + } + .column.is-11-mobile { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-mobile { + margin-left: 91.66667%; + } + .column.is-12-mobile { + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-left: 100%; + } +} + +@media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; + width: unset; + } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; + } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; + } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; + } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; + } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; + } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; + } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; + } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; + } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-left: 75%; + } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; + } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-left: 50%; + } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-left: 25%; + } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-left: 20%; + } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-left: 40%; + } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-left: 60%; + } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-left: 80%; + } + .column.is-0, .column.is-0-tablet { + flex: none; + width: 0%; + } + .column.is-offset-0, .column.is-offset-0-tablet { + margin-left: 0%; + } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.33333%; + } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-left: 8.33333%; + } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.66667%; + } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-left: 16.66667%; + } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; + } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-left: 25%; + } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.33333%; + } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-left: 33.33333%; + } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.66667%; + } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-left: 41.66667%; + } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; + } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-left: 50%; + } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.33333%; + } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-left: 58.33333%; + } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.66667%; + } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-left: 66.66667%; + } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; + } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-left: 75%; + } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.33333%; + } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-left: 83.33333%; + } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.66667%; + } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-left: 91.66667%; + } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; + } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-left: 100%; + } +} + +@media screen and (max-width: 1023px) { + .column.is-narrow-touch { + flex: none; + width: unset; + } + .column.is-full-touch { + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + flex: none; + width: 50%; + } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-left: 75%; + } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; + } + .column.is-offset-half-touch { + margin-left: 50%; + } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-touch { + margin-left: 25%; + } + .column.is-offset-one-fifth-touch { + margin-left: 20%; + } + .column.is-offset-two-fifths-touch { + margin-left: 40%; + } + .column.is-offset-three-fifths-touch { + margin-left: 60%; + } + .column.is-offset-four-fifths-touch { + margin-left: 80%; + } + .column.is-0-touch { + flex: none; + width: 0%; + } + .column.is-offset-0-touch { + margin-left: 0%; + } + .column.is-1-touch { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-touch { + margin-left: 8.33333%; + } + .column.is-2-touch { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-touch { + margin-left: 16.66667%; + } + .column.is-3-touch { + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-left: 25%; + } + .column.is-4-touch { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-touch { + margin-left: 33.33333%; + } + .column.is-5-touch { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-touch { + margin-left: 41.66667%; + } + .column.is-6-touch { + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-left: 50%; + } + .column.is-7-touch { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-touch { + margin-left: 58.33333%; + } + .column.is-8-touch { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-touch { + margin-left: 66.66667%; + } + .column.is-9-touch { + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-left: 75%; + } + .column.is-10-touch { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-touch { + margin-left: 83.33333%; + } + .column.is-11-touch { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-touch { + margin-left: 91.66667%; + } + .column.is-12-touch { + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-left: 100%; + } +} + +@media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + flex: none; + width: unset; + } + .column.is-full-desktop { + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; + } + .column.is-offset-half-desktop { + margin-left: 50%; + } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; + } + .column.is-0-desktop { + flex: none; + width: 0%; + } + .column.is-offset-0-desktop { + margin-left: 0%; + } + .column.is-1-desktop { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-desktop { + margin-left: 8.33333%; + } + .column.is-2-desktop { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-desktop { + margin-left: 16.66667%; + } + .column.is-3-desktop { + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-left: 25%; + } + .column.is-4-desktop { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-desktop { + margin-left: 33.33333%; + } + .column.is-5-desktop { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-desktop { + margin-left: 41.66667%; + } + .column.is-6-desktop { + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-left: 50%; + } + .column.is-7-desktop { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-desktop { + margin-left: 58.33333%; + } + .column.is-8-desktop { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-desktop { + margin-left: 66.66667%; + } + .column.is-9-desktop { + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-left: 75%; + } + .column.is-10-desktop { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-desktop { + margin-left: 83.33333%; + } + .column.is-11-desktop { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-desktop { + margin-left: 91.66667%; + } + .column.is-12-desktop { + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-left: 100%; + } +} + +@media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + flex: none; + width: unset; + } + .column.is-full-widescreen { + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-left: 50%; + } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; + } + .column.is-0-widescreen { + flex: none; + width: 0%; + } + .column.is-offset-0-widescreen { + margin-left: 0%; + } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; + } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; + } + .column.is-3-widescreen { + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-left: 25%; + } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; + } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; + } + .column.is-6-widescreen { + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-left: 50%; + } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; + } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; + } + .column.is-9-widescreen { + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-left: 75%; + } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; + } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; + } + .column.is-12-widescreen { + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-left: 100%; + } +} + +@media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + flex: none; + width: unset; + } + .column.is-full-fullhd { + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-left: 50%; + } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; + } + .column.is-0-fullhd { + flex: none; + width: 0%; + } + .column.is-offset-0-fullhd { + margin-left: 0%; + } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; + } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; + } + .column.is-3-fullhd { + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-left: 25%; + } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; + } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; + } + .column.is-6-fullhd { + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-left: 50%; + } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; + } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; + } + .column.is-9-fullhd { + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-left: 75%; + } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; + } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; + } + .column.is-12-fullhd { + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-left: 100%; + } +} + +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.columns:last-child { + margin-bottom: -0.75rem; +} + +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); +} + +.columns.is-centered { + justify-content: center; +} + +.columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; +} + +.columns.is-gapless > .column { + margin: 0; + padding: 0 !important; +} + +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} + +.columns.is-gapless:last-child { + margin-bottom: 0; +} + +.columns.is-mobile { + display: flex; +} + +.columns.is-multiline { + flex-wrap: wrap; +} + +.columns.is-vcentered { + align-items: center; +} + +@media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-desktop { + display: flex; + } +} + +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); +} + +.columns.is-variable > .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); +} + +.columns.is-variable.is-0 { + --columnGap: 0rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; + } +} + +.columns.is-variable.is-1 { + --columnGap: 0.25rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; + } +} + +.columns.is-variable.is-2 { + --columnGap: 0.5rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; + } +} + +.columns.is-variable.is-3 { + --columnGap: 0.75rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; + } +} + +.columns.is-variable.is-4 { + --columnGap: 1rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; + } +} + +.columns.is-variable.is-5 { + --columnGap: 1.25rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; + } +} + +.columns.is-variable.is-6 { + --columnGap: 1.5rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; + } +} + +.columns.is-variable.is-7 { + --columnGap: 1.75rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; + } +} + +.columns.is-variable.is-8 { + --columnGap: 2rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; + } +} + +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: -webkit-min-content; + min-height: -moz-min-content; + min-height: min-content; +} + +.tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.tile.is-ancestor:last-child { + margin-bottom: -0.75rem; +} + +.tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; +} + +.tile.is-child { + margin: 0 !important; +} + +.tile.is-parent { + padding: 0.75rem; +} + +.tile.is-vertical { + flex-direction: column; +} + +.tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; +} + +@media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; + } + .tile.is-1 { + flex: none; + width: 8.33333%; + } + .tile.is-2 { + flex: none; + width: 16.66667%; + } + .tile.is-3 { + flex: none; + width: 25%; + } + .tile.is-4 { + flex: none; + width: 33.33333%; + } + .tile.is-5 { + flex: none; + width: 41.66667%; + } + .tile.is-6 { + flex: none; + width: 50%; + } + .tile.is-7 { + flex: none; + width: 58.33333%; + } + .tile.is-8 { + flex: none; + width: 66.66667%; + } + .tile.is-9 { + flex: none; + width: 75%; + } + .tile.is-10 { + flex: none; + width: 83.33333%; + } + .tile.is-11 { + flex: none; + width: 91.66667%; + } + .tile.is-12 { + flex: none; + width: 100%; + } +} + +/* Bulma Helpers */ +.has-text-white { + color: white !important; +} + +a.has-text-white:hover, a.has-text-white:focus { + color: #e6e6e6 !important; +} + +.has-background-white { + background-color: white !important; +} + +.has-text-black { + color: #0a0a0a !important; +} + +a.has-text-black:hover, a.has-text-black:focus { + color: black !important; +} + +.has-background-black { + background-color: #0a0a0a !important; +} + +.has-text-light { + color: whitesmoke !important; +} + +a.has-text-light:hover, a.has-text-light:focus { + color: #dbdbdb !important; +} + +.has-background-light { + background-color: whitesmoke !important; +} + +.has-text-dark { + color: #363636 !important; +} + +a.has-text-dark:hover, a.has-text-dark:focus { + color: #1c1c1c !important; +} + +.has-background-dark { + background-color: #363636 !important; +} + +.has-text-primary { + color: #00d1b2 !important; +} + +a.has-text-primary:hover, a.has-text-primary:focus { + color: #009e86 !important; +} + +.has-background-primary { + background-color: #00d1b2 !important; +} + +.has-text-primary-light { + color: #ebfffc !important; +} + +a.has-text-primary-light:hover, a.has-text-primary-light:focus { + color: #b8fff4 !important; +} + +.has-background-primary-light { + background-color: #ebfffc !important; +} + +.has-text-primary-dark { + color: #00947e !important; +} + +a.has-text-primary-dark:hover, a.has-text-primary-dark:focus { + color: #00c7a9 !important; +} + +.has-background-primary-dark { + background-color: #00947e !important; +} + +.has-text-link { + color: #485fc7 !important; +} + +a.has-text-link:hover, a.has-text-link:focus { + color: #3449a8 !important; +} + +.has-background-link { + background-color: #485fc7 !important; +} + +.has-text-link-light { + color: #eff1fa !important; +} + +a.has-text-link-light:hover, a.has-text-link-light:focus { + color: #c8cfee !important; +} + +.has-background-link-light { + background-color: #eff1fa !important; +} + +.has-text-link-dark { + color: #3850b7 !important; +} + +a.has-text-link-dark:hover, a.has-text-link-dark:focus { + color: #576dcb !important; +} + +.has-background-link-dark { + background-color: #3850b7 !important; +} + +.has-text-info { + color: #3e8ed0 !important; +} + +a.has-text-info:hover, a.has-text-info:focus { + color: #2b74b1 !important; +} + +.has-background-info { + background-color: #3e8ed0 !important; +} + +.has-text-info-light { + color: #eff5fb !important; +} + +a.has-text-info-light:hover, a.has-text-info-light:focus { + color: #c6ddf1 !important; +} + +.has-background-info-light { + background-color: #eff5fb !important; +} + +.has-text-info-dark { + color: #296fa8 !important; +} + +a.has-text-info-dark:hover, a.has-text-info-dark:focus { + color: #368ace !important; +} + +.has-background-info-dark { + background-color: #296fa8 !important; +} + +.has-text-success { + color: #48c78e !important; +} + +a.has-text-success:hover, a.has-text-success:focus { + color: #34a873 !important; +} + +.has-background-success { + background-color: #48c78e !important; +} + +.has-text-success-light { + color: #effaf5 !important; +} + +a.has-text-success-light:hover, a.has-text-success-light:focus { + color: #c8eedd !important; +} + +.has-background-success-light { + background-color: #effaf5 !important; +} + +.has-text-success-dark { + color: #257953 !important; +} + +a.has-text-success-dark:hover, a.has-text-success-dark:focus { + color: #31a06e !important; +} + +.has-background-success-dark { + background-color: #257953 !important; +} + +.has-text-warning { + color: #ffe08a !important; +} + +a.has-text-warning:hover, a.has-text-warning:focus { + color: #ffd257 !important; +} + +.has-background-warning { + background-color: #ffe08a !important; +} + +.has-text-warning-light { + color: #fffaeb !important; +} + +a.has-text-warning-light:hover, a.has-text-warning-light:focus { + color: #ffecb8 !important; +} + +.has-background-warning-light { + background-color: #fffaeb !important; +} + +.has-text-warning-dark { + color: #946c00 !important; +} + +a.has-text-warning-dark:hover, a.has-text-warning-dark:focus { + color: #c79200 !important; +} + +.has-background-warning-dark { + background-color: #946c00 !important; +} + +.has-text-danger { + color: #f14668 !important; +} + +a.has-text-danger:hover, a.has-text-danger:focus { + color: #ee1742 !important; +} + +.has-background-danger { + background-color: #f14668 !important; +} + +.has-text-danger-light { + color: #feecf0 !important; +} + +a.has-text-danger-light:hover, a.has-text-danger-light:focus { + color: #fabdc9 !important; +} + +.has-background-danger-light { + background-color: #feecf0 !important; +} + +.has-text-danger-dark { + color: #cc0f35 !important; +} + +a.has-text-danger-dark:hover, a.has-text-danger-dark:focus { + color: #ee2049 !important; +} + +.has-background-danger-dark { + background-color: #cc0f35 !important; +} + +.has-text-black-bis { + color: #121212 !important; +} + +.has-background-black-bis { + background-color: #121212 !important; +} + +.has-text-black-ter { + color: #242424 !important; +} + +.has-background-black-ter { + background-color: #242424 !important; +} + +.has-text-grey-darker { + color: #363636 !important; +} + +.has-background-grey-darker { + background-color: #363636 !important; +} + +.has-text-grey-dark { + color: #4a4a4a !important; +} + +.has-background-grey-dark { + background-color: #4a4a4a !important; +} + +.has-text-grey { + color: #7a7a7a !important; +} + +.has-background-grey { + background-color: #7a7a7a !important; +} + +.has-text-grey-light { + color: #b5b5b5 !important; +} + +.has-background-grey-light { + background-color: #b5b5b5 !important; +} + +.has-text-grey-lighter { + color: #dbdbdb !important; +} + +.has-background-grey-lighter { + background-color: #dbdbdb !important; +} + +.has-text-white-ter { + color: whitesmoke !important; +} + +.has-background-white-ter { + background-color: whitesmoke !important; +} + +.has-text-white-bis { + color: #fafafa !important; +} + +.has-background-white-bis { + background-color: #fafafa !important; +} + +.is-flex-direction-row { + flex-direction: row !important; +} + +.is-flex-direction-row-reverse { + flex-direction: row-reverse !important; +} + +.is-flex-direction-column { + flex-direction: column !important; +} + +.is-flex-direction-column-reverse { + flex-direction: column-reverse !important; +} + +.is-flex-wrap-nowrap { + flex-wrap: nowrap !important; +} + +.is-flex-wrap-wrap { + flex-wrap: wrap !important; +} + +.is-flex-wrap-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.is-justify-content-flex-start { + justify-content: flex-start !important; +} + +.is-justify-content-flex-end { + justify-content: flex-end !important; +} + +.is-justify-content-center { + justify-content: center !important; +} + +.is-justify-content-space-between { + justify-content: space-between !important; +} + +.is-justify-content-space-around { + justify-content: space-around !important; +} + +.is-justify-content-space-evenly { + justify-content: space-evenly !important; +} + +.is-justify-content-start { + justify-content: start !important; +} + +.is-justify-content-end { + justify-content: end !important; +} + +.is-justify-content-left { + justify-content: left !important; +} + +.is-justify-content-right { + justify-content: right !important; +} + +.is-align-content-flex-start { + align-content: flex-start !important; +} + +.is-align-content-flex-end { + align-content: flex-end !important; +} + +.is-align-content-center { + align-content: center !important; +} + +.is-align-content-space-between { + align-content: space-between !important; +} + +.is-align-content-space-around { + align-content: space-around !important; +} + +.is-align-content-space-evenly { + align-content: space-evenly !important; +} + +.is-align-content-stretch { + align-content: stretch !important; +} + +.is-align-content-start { + align-content: start !important; +} + +.is-align-content-end { + align-content: end !important; +} + +.is-align-content-baseline { + align-content: baseline !important; +} + +.is-align-items-stretch { + align-items: stretch !important; +} + +.is-align-items-flex-start { + align-items: flex-start !important; +} + +.is-align-items-flex-end { + align-items: flex-end !important; +} + +.is-align-items-center { + align-items: center !important; +} + +.is-align-items-baseline { + align-items: baseline !important; +} + +.is-align-items-start { + align-items: start !important; +} + +.is-align-items-end { + align-items: end !important; +} + +.is-align-items-self-start { + align-items: self-start !important; +} + +.is-align-items-self-end { + align-items: self-end !important; +} + +.is-align-self-auto { + align-self: auto !important; +} + +.is-align-self-flex-start { + align-self: flex-start !important; +} + +.is-align-self-flex-end { + align-self: flex-end !important; +} + +.is-align-self-center { + align-self: center !important; +} + +.is-align-self-baseline { + align-self: baseline !important; +} + +.is-align-self-stretch { + align-self: stretch !important; +} + +.is-flex-grow-0 { + flex-grow: 0 !important; +} + +.is-flex-grow-1 { + flex-grow: 1 !important; +} + +.is-flex-grow-2 { + flex-grow: 2 !important; +} + +.is-flex-grow-3 { + flex-grow: 3 !important; +} + +.is-flex-grow-4 { + flex-grow: 4 !important; +} + +.is-flex-grow-5 { + flex-grow: 5 !important; +} + +.is-flex-shrink-0 { + flex-shrink: 0 !important; +} + +.is-flex-shrink-1 { + flex-shrink: 1 !important; +} + +.is-flex-shrink-2 { + flex-shrink: 2 !important; +} + +.is-flex-shrink-3 { + flex-shrink: 3 !important; +} + +.is-flex-shrink-4 { + flex-shrink: 4 !important; +} + +.is-flex-shrink-5 { + flex-shrink: 5 !important; +} + +.is-clearfix::after { + clear: both; + content: " "; + display: table; +} + +.is-pulled-left { + float: left !important; +} + +.is-pulled-right { + float: right !important; +} + +.is-radiusless { + border-radius: 0 !important; +} + +.is-shadowless { + box-shadow: none !important; +} + +.is-clickable { + cursor: pointer !important; + pointer-events: all !important; +} + +.is-clipped { + overflow: hidden !important; +} + +.is-relative { + position: relative !important; +} + +.is-marginless { + margin: 0 !important; +} + +.is-paddingless { + padding: 0 !important; +} + +.m-0 { + margin: 0 !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mr-0 { + margin-right: 0 !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.ml-0 { + margin-left: 0 !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mr-1 { + margin-right: 0.25rem !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1 { + margin-left: 0.25rem !important; +} + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mr-2 { + margin-right: 0.5rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2 { + margin-left: 0.5rem !important; +} + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.m-3 { + margin: 0.75rem !important; +} + +.mt-3 { + margin-top: 0.75rem !important; +} + +.mr-3 { + margin-right: 0.75rem !important; +} + +.mb-3 { + margin-bottom: 0.75rem !important; +} + +.ml-3 { + margin-left: 0.75rem !important; +} + +.mx-3 { + margin-left: 0.75rem !important; + margin-right: 0.75rem !important; +} + +.my-3 { + margin-top: 0.75rem !important; + margin-bottom: 0.75rem !important; +} + +.m-4 { + margin: 1rem !important; +} + +.mt-4 { + margin-top: 1rem !important; +} + +.mr-4 { + margin-right: 1rem !important; +} + +.mb-4 { + margin-bottom: 1rem !important; +} + +.ml-4 { + margin-left: 1rem !important; +} + +.mx-4 { + margin-left: 1rem !important; + margin-right: 1rem !important; +} + +.my-4 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.m-5 { + margin: 1.5rem !important; +} + +.mt-5 { + margin-top: 1.5rem !important; +} + +.mr-5 { + margin-right: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 1.5rem !important; +} + +.ml-5 { + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; +} + +.my-5 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.m-6 { + margin: 3rem !important; +} + +.mt-6 { + margin-top: 3rem !important; +} + +.mr-6 { + margin-right: 3rem !important; +} + +.mb-6 { + margin-bottom: 3rem !important; +} + +.ml-6 { + margin-left: 3rem !important; +} + +.mx-6 { + margin-left: 3rem !important; + margin-right: 3rem !important; +} + +.my-6 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.mr-auto { + margin-right: auto !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ml-auto { + margin-left: auto !important; +} + +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pr-0 { + padding-right: 0 !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pl-0 { + padding-left: 0 !important; +} + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pr-1 { + padding-right: 0.25rem !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1 { + padding-left: 0.25rem !important; +} + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pr-2 { + padding-right: 0.5rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2 { + padding-left: 0.5rem !important; +} + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.p-3 { + padding: 0.75rem !important; +} + +.pt-3 { + padding-top: 0.75rem !important; +} + +.pr-3 { + padding-right: 0.75rem !important; +} + +.pb-3 { + padding-bottom: 0.75rem !important; +} + +.pl-3 { + padding-left: 0.75rem !important; +} + +.px-3 { + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; +} + +.py-3 { + padding-top: 0.75rem !important; + padding-bottom: 0.75rem !important; +} + +.p-4 { + padding: 1rem !important; +} + +.pt-4 { + padding-top: 1rem !important; +} + +.pr-4 { + padding-right: 1rem !important; +} + +.pb-4 { + padding-bottom: 1rem !important; +} + +.pl-4 { + padding-left: 1rem !important; +} + +.px-4 { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +.py-4 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.p-5 { + padding: 1.5rem !important; +} + +.pt-5 { + padding-top: 1.5rem !important; +} + +.pr-5 { + padding-right: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 1.5rem !important; +} + +.pl-5 { + padding-left: 1.5rem !important; +} + +.px-5 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; +} + +.py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.p-6 { + padding: 3rem !important; +} + +.pt-6 { + padding-top: 3rem !important; +} + +.pr-6 { + padding-right: 3rem !important; +} + +.pb-6 { + padding-bottom: 3rem !important; +} + +.pl-6 { + padding-left: 3rem !important; +} + +.px-6 { + padding-left: 3rem !important; + padding-right: 3rem !important; +} + +.py-6 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.p-auto { + padding: auto !important; +} + +.pt-auto { + padding-top: auto !important; +} + +.pr-auto { + padding-right: auto !important; +} + +.pb-auto { + padding-bottom: auto !important; +} + +.pl-auto { + padding-left: auto !important; +} + +.px-auto { + padding-left: auto !important; + padding-right: auto !important; +} + +.py-auto { + padding-top: auto !important; + padding-bottom: auto !important; +} + +.is-size-1 { + font-size: 3rem !important; +} + +.is-size-2 { + font-size: 2.5rem !important; +} + +.is-size-3 { + font-size: 2rem !important; +} + +.is-size-4 { + font-size: 1.5rem !important; +} + +.is-size-5 { + font-size: 1.25rem !important; +} + +.is-size-6 { + font-size: 1rem !important; +} + +.is-size-7 { + font-size: 0.75rem !important; +} + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; + } + .is-size-2-mobile { + font-size: 2.5rem !important; + } + .is-size-3-mobile { + font-size: 2rem !important; + } + .is-size-4-mobile { + font-size: 1.5rem !important; + } + .is-size-5-mobile { + font-size: 1.25rem !important; + } + .is-size-6-mobile { + font-size: 1rem !important; + } + .is-size-7-mobile { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; + } + .is-size-2-tablet { + font-size: 2.5rem !important; + } + .is-size-3-tablet { + font-size: 2rem !important; + } + .is-size-4-tablet { + font-size: 1.5rem !important; + } + .is-size-5-tablet { + font-size: 1.25rem !important; + } + .is-size-6-tablet { + font-size: 1rem !important; + } + .is-size-7-tablet { + font-size: 0.75rem !important; + } +} + +@media screen and (max-width: 1023px) { + .is-size-1-touch { + font-size: 3rem !important; + } + .is-size-2-touch { + font-size: 2.5rem !important; + } + .is-size-3-touch { + font-size: 2rem !important; + } + .is-size-4-touch { + font-size: 1.5rem !important; + } + .is-size-5-touch { + font-size: 1.25rem !important; + } + .is-size-6-touch { + font-size: 1rem !important; + } + .is-size-7-touch { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1024px) { + .is-size-1-desktop { + font-size: 3rem !important; + } + .is-size-2-desktop { + font-size: 2.5rem !important; + } + .is-size-3-desktop { + font-size: 2rem !important; + } + .is-size-4-desktop { + font-size: 1.5rem !important; + } + .is-size-5-desktop { + font-size: 1.25rem !important; + } + .is-size-6-desktop { + font-size: 1rem !important; + } + .is-size-7-desktop { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1216px) { + .is-size-1-widescreen { + font-size: 3rem !important; + } + .is-size-2-widescreen { + font-size: 2.5rem !important; + } + .is-size-3-widescreen { + font-size: 2rem !important; + } + .is-size-4-widescreen { + font-size: 1.5rem !important; + } + .is-size-5-widescreen { + font-size: 1.25rem !important; + } + .is-size-6-widescreen { + font-size: 1rem !important; + } + .is-size-7-widescreen { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1408px) { + .is-size-1-fullhd { + font-size: 3rem !important; + } + .is-size-2-fullhd { + font-size: 2.5rem !important; + } + .is-size-3-fullhd { + font-size: 2rem !important; + } + .is-size-4-fullhd { + font-size: 1.5rem !important; + } + .is-size-5-fullhd { + font-size: 1.25rem !important; + } + .is-size-6-fullhd { + font-size: 1rem !important; + } + .is-size-7-fullhd { + font-size: 0.75rem !important; + } +} + +.has-text-centered { + text-align: center !important; +} + +.has-text-justified { + text-align: justify !important; +} + +.has-text-left { + text-align: left !important; +} + +.has-text-right { + text-align: right !important; +} + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-centered-tablet-only { + text-align: center !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-centered-touch { + text-align: center !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-centered-desktop { + text-align: center !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-centered-desktop-only { + text-align: center !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-centered-widescreen { + text-align: center !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-centered-widescreen-only { + text-align: center !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-centered-fullhd { + text-align: center !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-justified-tablet-only { + text-align: justify !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-justified-touch { + text-align: justify !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-justified-desktop { + text-align: justify !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-justified-desktop-only { + text-align: justify !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-justified-widescreen { + text-align: justify !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-justified-widescreen-only { + text-align: justify !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-justified-fullhd { + text-align: justify !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-left-tablet-only { + text-align: left !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-left-touch { + text-align: left !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-left-desktop { + text-align: left !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-left-desktop-only { + text-align: left !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-left-widescreen { + text-align: left !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-left-widescreen-only { + text-align: left !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-left-fullhd { + text-align: left !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-right-tablet-only { + text-align: right !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-right-touch { + text-align: right !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-right-desktop { + text-align: right !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-right-desktop-only { + text-align: right !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-right-widescreen { + text-align: right !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-right-widescreen-only { + text-align: right !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-right-fullhd { + text-align: right !important; + } +} + +.is-capitalized { + text-transform: capitalize !important; +} + +.is-lowercase { + text-transform: lowercase !important; +} + +.is-uppercase { + text-transform: uppercase !important; +} + +.is-italic { + font-style: italic !important; +} + +.is-underlined { + text-decoration: underline !important; +} + +.has-text-weight-light { + font-weight: 300 !important; +} + +.has-text-weight-normal { + font-weight: 400 !important; +} + +.has-text-weight-medium { + font-weight: 500 !important; +} + +.has-text-weight-semibold { + font-weight: 600 !important; +} + +.has-text-weight-bold { + font-weight: 700 !important; +} + +.is-family-primary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-secondary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-sans-serif { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-monospace { + font-family: monospace !important; +} + +.is-family-code { + font-family: monospace !important; +} + +.is-block { + display: block !important; +} + +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; + } +} + +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-block-tablet-only { + display: block !important; + } +} + +@media screen and (max-width: 1023px) { + .is-block-touch { + display: block !important; + } +} + +@media screen and (min-width: 1024px) { + .is-block-desktop { + display: block !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-block-desktop-only { + display: block !important; + } +} + +@media screen and (min-width: 1216px) { + .is-block-widescreen { + display: block !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-block-widescreen-only { + display: block !important; + } +} + +@media screen and (min-width: 1408px) { + .is-block-fullhd { + display: block !important; + } +} + +.is-flex { + display: flex !important; +} + +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; + } +} + +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-flex-tablet-only { + display: flex !important; + } +} + +@media screen and (max-width: 1023px) { + .is-flex-touch { + display: flex !important; + } +} + +@media screen and (min-width: 1024px) { + .is-flex-desktop { + display: flex !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-flex-desktop-only { + display: flex !important; + } +} + +@media screen and (min-width: 1216px) { + .is-flex-widescreen { + display: flex !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-flex-widescreen-only { + display: flex !important; + } +} + +@media screen and (min-width: 1408px) { + .is-flex-fullhd { + display: flex !important; + } +} + +.is-inline { + display: inline !important; +} + +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-tablet-only { + display: inline !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-touch { + display: inline !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-desktop { + display: inline !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-desktop-only { + display: inline !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-widescreen { + display: inline !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-widescreen-only { + display: inline !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-fullhd { + display: inline !important; + } +} + +.is-inline-block { + display: inline-block !important; +} + +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-block-tablet-only { + display: inline-block !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-block-touch { + display: inline-block !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-block-desktop { + display: inline-block !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-block-desktop-only { + display: inline-block !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-block-widescreen { + display: inline-block !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-block-widescreen-only { + display: inline-block !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-block-fullhd { + display: inline-block !important; + } +} + +.is-inline-flex { + display: inline-flex !important; +} + +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-flex-touch { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-flex-desktop { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-flex-widescreen { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-flex-fullhd { + display: inline-flex !important; + } +} + +.is-hidden { + display: none !important; +} + +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; +} + +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; + } +} + +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-hidden-tablet-only { + display: none !important; + } +} + +@media screen and (max-width: 1023px) { + .is-hidden-touch { + display: none !important; + } +} + +@media screen and (min-width: 1024px) { + .is-hidden-desktop { + display: none !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-hidden-desktop-only { + display: none !important; + } +} + +@media screen and (min-width: 1216px) { + .is-hidden-widescreen { + display: none !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-hidden-widescreen-only { + display: none !important; + } +} + +@media screen and (min-width: 1408px) { + .is-hidden-fullhd { + display: none !important; + } +} + +.is-invisible { + visibility: hidden !important; +} + +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; + } +} + +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-invisible-tablet-only { + visibility: hidden !important; + } +} + +@media screen and (max-width: 1023px) { + .is-invisible-touch { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1024px) { + .is-invisible-desktop { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-invisible-desktop-only { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1216px) { + .is-invisible-widescreen { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-invisible-widescreen-only { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1408px) { + .is-invisible-fullhd { + visibility: hidden !important; + } +} + +/* Bulma Layout */ +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.hero .navbar { + background: none; +} + +.hero .tabs ul { + border-bottom: none; +} + +.hero.is-white { + background-color: white; + color: #0a0a0a; +} + +.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-white strong { + color: inherit; +} + +.hero.is-white .title { + color: #0a0a0a; +} + +.hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); +} + +.hero.is-white .subtitle a:not(.button), +.hero.is-white .subtitle strong { + color: #0a0a0a; +} + +@media screen and (max-width: 1023px) { + .hero.is-white .navbar-menu { + background-color: white; + } +} + +.hero.is-white .navbar-item, +.hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); +} + +.hero.is-white a.navbar-item:hover, .hero.is-white a.navbar-item.is-active, +.hero.is-white .navbar-link:hover, +.hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; +} + +.hero.is-white .tabs a:hover { + opacity: 1; +} + +.hero.is-white .tabs li.is-active a { + color: white !important; + opacity: 1; +} + +.hero.is-white .tabs.is-boxed a, .hero.is-white .tabs.is-toggle a { + color: #0a0a0a; +} + +.hero.is-white .tabs.is-boxed a:hover, .hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-white .tabs.is-boxed li.is-active a, .hero.is-white .tabs.is-boxed li.is-active a:hover, .hero.is-white .tabs.is-toggle li.is-active a, .hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); + } +} + +.hero.is-black { + background-color: #0a0a0a; + color: white; +} + +.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-black strong { + color: inherit; +} + +.hero.is-black .title { + color: white; +} + +.hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-black .subtitle a:not(.button), +.hero.is-black .subtitle strong { + color: white; +} + +@media screen and (max-width: 1023px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; + } +} + +.hero.is-black .navbar-item, +.hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-black a.navbar-item:hover, .hero.is-black a.navbar-item.is-active, +.hero.is-black .navbar-link:hover, +.hero.is-black .navbar-link.is-active { + background-color: black; + color: white; +} + +.hero.is-black .tabs a { + color: white; + opacity: 0.9; +} + +.hero.is-black .tabs a:hover { + opacity: 1; +} + +.hero.is-black .tabs li.is-active a { + color: #0a0a0a !important; + opacity: 1; +} + +.hero.is-black .tabs.is-boxed a, .hero.is-black .tabs.is-toggle a { + color: white; +} + +.hero.is-black .tabs.is-boxed a:hover, .hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-black .tabs.is-boxed li.is-active a, .hero.is-black .tabs.is-boxed li.is-active a:hover, .hero.is-black .tabs.is-toggle li.is-active a, .hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); + } +} + +.hero.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-light strong { + color: inherit; +} + +.hero.is-light .title { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .subtitle { + color: rgba(0, 0, 0, 0.9); +} + +.hero.is-light .subtitle a:not(.button), +.hero.is-light .subtitle strong { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (max-width: 1023px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; + } +} + +.hero.is-light .navbar-item, +.hero.is-light .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light a.navbar-item:hover, .hero.is-light a.navbar-item.is-active, +.hero.is-light .navbar-link:hover, +.hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; +} + +.hero.is-light .tabs a:hover { + opacity: 1; +} + +.hero.is-light .tabs li.is-active a { + color: whitesmoke !important; + opacity: 1; +} + +.hero.is-light .tabs.is-boxed a, .hero.is-light .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .tabs.is-boxed a:hover, .hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-light .tabs.is-boxed li.is-active a, .hero.is-light .tabs.is-boxed li.is-active a:hover, .hero.is-light .tabs.is-toggle li.is-active a, .hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); + } +} + +.hero.is-dark { + background-color: #363636; + color: #fff; +} + +.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-dark strong { + color: inherit; +} + +.hero.is-dark .title { + color: #fff; +} + +.hero.is-dark .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-dark .subtitle a:not(.button), +.hero.is-dark .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-dark .navbar-menu { + background-color: #363636; + } +} + +.hero.is-dark .navbar-item, +.hero.is-dark .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-dark a.navbar-item:hover, .hero.is-dark a.navbar-item.is-active, +.hero.is-dark .navbar-link:hover, +.hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; +} + +.hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-dark .tabs a:hover { + opacity: 1; +} + +.hero.is-dark .tabs li.is-active a { + color: #363636 !important; + opacity: 1; +} + +.hero.is-dark .tabs.is-boxed a, .hero.is-dark .tabs.is-toggle a { + color: #fff; +} + +.hero.is-dark .tabs.is-boxed a:hover, .hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-dark .tabs.is-boxed li.is-active a, .hero.is-dark .tabs.is-boxed li.is-active a:hover, .hero.is-dark .tabs.is-toggle li.is-active a, .hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; +} + +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); + } +} + +.hero.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-primary strong { + color: inherit; +} + +.hero.is-primary .title { + color: #fff; +} + +.hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-primary .subtitle a:not(.button), +.hero.is-primary .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; + } +} + +.hero.is-primary .navbar-item, +.hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-primary a.navbar-item:hover, .hero.is-primary a.navbar-item.is-active, +.hero.is-primary .navbar-link:hover, +.hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-primary .tabs a:hover { + opacity: 1; +} + +.hero.is-primary .tabs li.is-active a { + color: #00d1b2 !important; + opacity: 1; +} + +.hero.is-primary .tabs.is-boxed a, .hero.is-primary .tabs.is-toggle a { + color: #fff; +} + +.hero.is-primary .tabs.is-boxed a:hover, .hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-primary .tabs.is-boxed li.is-active a, .hero.is-primary .tabs.is-boxed li.is-active a:hover, .hero.is-primary .tabs.is-toggle li.is-active a, .hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; +} + +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); + } +} + +.hero.is-link { + background-color: #485fc7; + color: #fff; +} + +.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-link strong { + color: inherit; +} + +.hero.is-link .title { + color: #fff; +} + +.hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-link .subtitle a:not(.button), +.hero.is-link .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-link .navbar-menu { + background-color: #485fc7; + } +} + +.hero.is-link .navbar-item, +.hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-link a.navbar-item:hover, .hero.is-link a.navbar-item.is-active, +.hero.is-link .navbar-link:hover, +.hero.is-link .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; +} + +.hero.is-link .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-link .tabs a:hover { + opacity: 1; +} + +.hero.is-link .tabs li.is-active a { + color: #485fc7 !important; + opacity: 1; +} + +.hero.is-link .tabs.is-boxed a, .hero.is-link .tabs.is-toggle a { + color: #fff; +} + +.hero.is-link .tabs.is-boxed a:hover, .hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-link .tabs.is-boxed li.is-active a, .hero.is-link .tabs.is-boxed li.is-active a:hover, .hero.is-link .tabs.is-toggle li.is-active a, .hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #485fc7; +} + +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, #2959b3 0%, #485fc7 71%, #5658d2 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #2959b3 0%, #485fc7 71%, #5658d2 100%); + } +} + +.hero.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-info strong { + color: inherit; +} + +.hero.is-info .title { + color: #fff; +} + +.hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-info .subtitle a:not(.button), +.hero.is-info .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-info .navbar-menu { + background-color: #3e8ed0; + } +} + +.hero.is-info .navbar-item, +.hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-info a.navbar-item:hover, .hero.is-info a.navbar-item.is-active, +.hero.is-info .navbar-link:hover, +.hero.is-info .navbar-link.is-active { + background-color: #3082c5; + color: #fff; +} + +.hero.is-info .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-info .tabs a:hover { + opacity: 1; +} + +.hero.is-info .tabs li.is-active a { + color: #3e8ed0 !important; + opacity: 1; +} + +.hero.is-info .tabs.is-boxed a, .hero.is-info .tabs.is-toggle a { + color: #fff; +} + +.hero.is-info .tabs.is-boxed a:hover, .hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-info .tabs.is-boxed li.is-active a, .hero.is-info .tabs.is-boxed li.is-active a:hover, .hero.is-info .tabs.is-toggle li.is-active a, .hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3e8ed0; +} + +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, #208fbc 0%, #3e8ed0 71%, #4d83db 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #208fbc 0%, #3e8ed0 71%, #4d83db 100%); + } +} + +.hero.is-success { + background-color: #48c78e; + color: #fff; +} + +.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-success strong { + color: inherit; +} + +.hero.is-success .title { + color: #fff; +} + +.hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-success .subtitle a:not(.button), +.hero.is-success .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-success .navbar-menu { + background-color: #48c78e; + } +} + +.hero.is-success .navbar-item, +.hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-success a.navbar-item:hover, .hero.is-success a.navbar-item.is-active, +.hero.is-success .navbar-link:hover, +.hero.is-success .navbar-link.is-active { + background-color: #3abb81; + color: #fff; +} + +.hero.is-success .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-success .tabs a:hover { + opacity: 1; +} + +.hero.is-success .tabs li.is-active a { + color: #48c78e !important; + opacity: 1; +} + +.hero.is-success .tabs.is-boxed a, .hero.is-success .tabs.is-toggle a { + color: #fff; +} + +.hero.is-success .tabs.is-boxed a:hover, .hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-success .tabs.is-boxed li.is-active a, .hero.is-success .tabs.is-boxed li.is-active a:hover, .hero.is-success .tabs.is-toggle li.is-active a, .hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #48c78e; +} + +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, #29b35e 0%, #48c78e 71%, #56d2af 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #29b35e 0%, #48c78e 71%, #56d2af 100%); + } +} + +.hero.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-warning strong { + color: inherit; +} + +.hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); +} + +.hero.is-warning .subtitle a:not(.button), +.hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (max-width: 1023px) { + .hero.is-warning .navbar-menu { + background-color: #ffe08a; + } +} + +.hero.is-warning .navbar-item, +.hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a.navbar-item:hover, .hero.is-warning a.navbar-item.is-active, +.hero.is-warning .navbar-link:hover, +.hero.is-warning .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; +} + +.hero.is-warning .tabs a:hover { + opacity: 1; +} + +.hero.is-warning .tabs li.is-active a { + color: #ffe08a !important; + opacity: 1; +} + +.hero.is-warning .tabs.is-boxed a, .hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs.is-boxed a:hover, .hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-warning .tabs.is-boxed li.is-active a, .hero.is-warning .tabs.is-boxed li.is-active a:hover, .hero.is-warning .tabs.is-toggle li.is-active a, .hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffb657 0%, #ffe08a 71%, #fff6a3 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffb657 0%, #ffe08a 71%, #fff6a3 100%); + } +} + +.hero.is-danger { + background-color: #f14668; + color: #fff; +} + +.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-danger strong { + color: inherit; +} + +.hero.is-danger .title { + color: #fff; +} + +.hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-danger .subtitle a:not(.button), +.hero.is-danger .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-danger .navbar-menu { + background-color: #f14668; + } +} + +.hero.is-danger .navbar-item, +.hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-danger a.navbar-item:hover, .hero.is-danger a.navbar-item.is-active, +.hero.is-danger .navbar-link:hover, +.hero.is-danger .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} + +.hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-danger .tabs a:hover { + opacity: 1; +} + +.hero.is-danger .tabs li.is-active a { + color: #f14668 !important; + opacity: 1; +} + +.hero.is-danger .tabs.is-boxed a, .hero.is-danger .tabs.is-toggle a { + color: #fff; +} + +.hero.is-danger .tabs.is-boxed a:hover, .hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-danger .tabs.is-boxed li.is-active a, .hero.is-danger .tabs.is-boxed li.is-active a:hover, .hero.is-danger .tabs.is-toggle li.is-active a, .hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #f14668; +} + +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); + } +} + +.hero.is-small .hero-body { + padding: 1.5rem; +} + +@media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding: 9rem 4.5rem; + } +} + +@media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding: 18rem 6rem; + } +} + +.hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; +} + +.hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; +} + +.hero.is-halfheight { + min-height: 50vh; +} + +.hero.is-fullheight { + min-height: 100vh; +} + +.hero-video { + overflow: hidden; +} + +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); +} + +.hero-video.is-transparent { + opacity: 0.3; +} + +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} + +.hero-buttons { + margin-top: 1.5rem; +} + +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +@media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; + } +} + +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; +} + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; +} + +@media screen and (min-width: 769px), print { + .hero-body { + padding: 3rem 3rem; + } +} + +.section { + padding: 3rem 1.5rem; +} + +@media screen and (min-width: 1024px) { + .section { + padding: 3rem 3rem; + } + .section.is-medium { + padding: 9rem 4.5rem; + } + .section.is-large { + padding: 18rem 6rem; + } +} + +.footer { + background-color: #fafafa; + padding: 3rem 1.5rem 6rem; +} +/*# sourceMappingURL=bulma.css.map */ \ No newline at end of file diff --git a/templ/examples/counter-basic/assets/bulma.css.map b/templ/examples/counter-basic/assets/bulma.css.map new file mode 100644 index 0000000..dbe97a3 --- /dev/null +++ b/templ/examples/counter-basic/assets/bulma.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../bulma.sass","../sass/utilities/_all.sass","../sass/utilities/extends.sass","../sass/utilities/controls.sass","../sass/utilities/initial-variables.sass","bulma.css","../sass/utilities/mixins.sass","../sass/base/_all.sass","../sass/base/minireset.sass","../sass/base/generic.sass","../sass/utilities/derived-variables.sass","../sass/base/animations.sass","../sass/elements/_all.sass","../sass/elements/box.sass","../sass/elements/button.sass","../sass/utilities/functions.sass","../sass/elements/container.sass","../sass/elements/content.sass","../sass/elements/icon.sass","../sass/elements/image.sass","../sass/elements/notification.sass","../sass/elements/progress.sass","../sass/elements/table.sass","../sass/elements/tag.sass","../sass/elements/title.sass","../sass/elements/other.sass","../sass/form/_all.sass","../sass/form/shared.sass","../sass/form/input-textarea.sass","../sass/form/checkbox-radio.sass","../sass/form/select.sass","../sass/form/file.sass","../sass/form/tools.sass","../sass/components/_all.sass","../sass/components/breadcrumb.sass","../sass/components/card.sass","../sass/components/dropdown.sass","../sass/components/level.sass","../sass/components/media.sass","../sass/components/menu.sass","../sass/components/message.sass","../sass/components/modal.sass","../sass/components/navbar.sass","../sass/components/pagination.sass","../sass/components/panel.sass","../sass/components/tabs.sass","../sass/grid/_all.sass","../sass/grid/columns.sass","../sass/grid/tiles.sass","../sass/helpers/_all.sass","../sass/helpers/color.sass","../sass/helpers/flexbox.sass","../sass/helpers/float.sass","../sass/helpers/other.sass","../sass/helpers/overflow.sass","../sass/helpers/position.sass","../sass/helpers/spacing.sass","../sass/helpers/typography.sass","../sass/helpers/visibility.sass","../sass/layout/_all.sass","../sass/layout/hero.sass","../sass/layout/section.sass","../sass/layout/footer.sass"],"names":[],"mappings":"AACA,6DAAA;ACDA,oBAAA;ACEA;;;;;ECYE,qBAAqB;EACrB,wBAAwB;EACxB,mBAAmB;EACnB,6BAA+C;EAC/C,kBCoDU;EDnDV,gBAAgB;EAChB,oBAAoB;EACpB,eCgBW;EDfX,aAfoB;EAgBpB,2BAA2B;EAC3B,gBAhBuB;EAiBvB,iCAf+D;EAgB/D,gCAfkE;EAgBlE,iCAhBkE;EAiBlE,8BAlB+D;EAmB/D,kBAAkB;EAClB,mBAAmB;AENrB;;AFQE;;;;;;;;;;;;;;;;;EAIE,aAAa;AEQjB;;AFPE;;;;;;;;;;;;;;;;EAEE,mBAAmB;AEwBvB;;AH1DA;;;;EI4LE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;AD3HnB;;AHlEA;EIgME,6BAD8B;EAE9B,kBAAkB;EAClB,eAAe;EACf,aAAa;EACb,YAAY;EACZ,cAAc;EACd,eAAe;EACf,qBAAqB;EACrB,oBAAoB;EACpB,kBAAkB;EAClB,QAAQ;EACR,yBAAyB;EACzB,wBAAwB;EACxB,cAAc;AD1HhB;;AC6HE;;EACE,qBFzKkB;ACgDtB;;AHlFA;EImLE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;EAwBjB,qBAAqB;EACrB,wBAAwB;EACxB,uCF7N2B;EE8N3B,YAAY;EACZ,qBFzJqB;EE0JrB,eAAe;EACf,oBAAoB;EACpB,qBAAqB;EACrB,YAAY;EACZ,cAAc;EACd,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,aAAa;EACb,kBAAkB;EAClB,mBAAmB;EACnB,WAAW;ADpHb;;ACqHE;EAEE,uBFpO2B;EEqO3B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;ADnHnC;;ACoHE;EACE,WAAW;EACX,UAAU;ADjHd;;ACkHE;EACE,WAAW;EACX,UAAU;AD/Gd;;ACgHE;EAEE,uCFjQyB;ACmJ7B;;AC+GE;EACE,uCFnQyB;ACuJ7B;;AC8GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;AD3Gf;;AC4GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADzGf;;AC0GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADvGf;;AHnKA;EI6QE,mDAA2C;UAA3C,2CAA2C;EAC3C,yBFrR4B;EEsR5B,qBFxNqB;EEyNrB,+BAA+B;EAC/B,6BAA6B;EAC7B,WAAW;EACX,cAAc;EACd,WAAW;EACX,kBAAkB;EAClB,UAAU;ADtGZ;;AH7KA;;;;;;;;;;;;;;;;;EIsRE,SADuB;EAEvB,OAFuB;EAGvB,kBAAkB;EAClB,QAJuB;EAKvB,MALuB;ADhFzB;;AHlMA;EIqDE,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,mBAAmB;EACnB,oBAAoB;EACpB,cAAc;EACd,SAAS;EACT,UAAU;ADiJZ;;AEtOA,eAAA;ACAA,0EAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;EAuBE,SAAS;EACT,UAAU;AHyOZ;;AGtOA;;;;;;EAME,eAAe;EACf,mBAAmB;AHyOrB;;AGtOA;EACE,gBAAgB;AHyOlB;;AGtOA;;;;EAIE,SAAS;AHyOX;;AGtOA;EACE,sBAAsB;AHyOxB;;AGvOA;EAII,mBAAmB;AHuOvB;;AGpOA;;EAEE,YAAY;EACZ,eAAe;AHuOjB;;AGpOA;EACE,SAAS;AHuOX;;AGpOA;EACE,yBAAyB;EACzB,iBAAiB;AHuOnB;;AGrOA;;EAEE,UAAU;AHwOZ;;AG1OA;;EAII,mBAAmB;AH2OvB;;AGvQA;EChBE,uBLnB6B;EKoB7B,eAhCc;EAiCd,kCAAkC;EAClC,mCAAmC;EACnC,gBAlCoB;EAmCpB,kBAhCsB;EAiCtB,kBAhCsB;EAiCtB,kCApCiC;EAqCjC,8BAAsB;KAAtB,2BAAsB;UAAtB,sBAAsB;AJ2RxB;;AIzRA;;;;;;;EAOE,cAAc;AJ4RhB;;AI1RA;;;;;;EAME,oLL/ByL;AC4T3L;;AI3RA;;EAEE,6BAA6B;EAC7B,4BAA4B;EAC5B,sBLpC0B;ACkU5B;;AI5RA;EACE,cL7D4B;EK8D5B,cA1DkB;EA2DlB,gBL7BiB;EK8BjB,gBA1DoB;AJyVtB;;AI3RA;EACE,cLtDgC;EKuDhC,eAAe;EACf,qBAAqB;AJ8RvB;;AIjSA;EAKI,mBAAmB;AJgSvB;;AIrSA;EAOI,cL5E0B;AC8W9B;;AIhSA;EACE,4BLxE4B;EKyE5B,cCnBsB;EDoBtB,kBArEiB;EAsEjB,mBAvEkB;EAwElB,4BAzEgC;AJ4WlC;;AIjSA;EACE,4BL/E4B;EKgF5B,YAAY;EACZ,cAAc;EACd,WAxEa;EAyEb,gBAxEkB;AJ4WpB;;AIlSA;EACE,YAAY;EACZ,eAAe;AJqSjB;;AInSA;;EAEE,wBAAwB;AJsS1B;;AIpSA;EACE,kBAvFuB;AJ8XzB;;AIrSA;EACE,mBAAmB;EACnB,oBAAoB;AJwStB;;AItSA;EACE,cL5G4B;EK6G5B,gBLvEe;ACgXjB;;AIrSA;EACE,YAAY;AJwSd;;AItSA;EHvDE,iCAAiC;EGyDjC,4BL/G4B;EKgH5B,cLtH4B;EKuH5B,kBAjGqB;EAkGrB,gBAAgB;EAChB,uBAlG0B;EAmG1B,gBAAgB;EAChB,iBAAiB;AJySnB;;AIjTA;EAUI,6BAA6B;EAC7B,mBAAmB;EACnB,cAvGoB;EAwGpB,UAAU;AJ2Sd;;AIzSA;;EAGI,mBAAmB;AJ2SvB;;AI9SA;;EAKM,mBAAmB;AJ8SzB;;AInTA;EAOI,cL1I0B;AC0b9B;;AMhcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AMzcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AOzcA,mBAAA;ACWA;EAEE,uBTE6B;ESD7B,kBTyDgB;ESxDhB,0FTb2B;ESc3B,cTT4B;ESU5B,cAAc;EACd,gBAZmB;AR6crB;;AQ/bA;EAGI,yETD8B;ACiclC;;AQncA;EAKI,oETH8B;ACqclC;;AS/ZA;EAGE,uBVhD6B;EUiD7B,qBVtD4B;EUuD5B,iBX5DwB;EW6DxB,cV5D4B;EU6D5B,eAAe;EAGf,uBAAuB;EACvB,iCA7D6D;EA8D7D,iBA7D6B;EA8D7B,kBA9D6B;EA+D7B,8BAhE6D;EAiE7D,kBAAkB;EAClB,mBAAmB;AT8ZrB;;AS9aA;EAkBI,cAAc;ATgalB;;ASlbA;EAwBM,aAAa;EACb,YAAY;AT8ZlB;;ASvbA;ERwHI,+BQ7FsG;ER6FtG,oBQ5FmE;ATgavE;;AS5bA;ERwHI,mBQ1FmE;ER0FnE,gCQzFsG;ATka1G;;ASjcA;EAiCM,+BAAiF;EACjF,gCAAkF;AToaxF;;AStcA;EAsCI,qBVzF0B;EU0F1B,cV7F0B;ACigB9B;;AS3cA;EA0CI,qBVhF8B;EUiF9B,cVjG0B;ACsgB9B;;AShdA;EA6CM,iDVnF4B;AC0flC;;ASpdA;EAgDI,qBVrG0B;EUsG1B,cVvG0B;AC+gB9B;;ASzdA;EAoDI,6BAA6B;EAC7B,yBAAyB;EACzB,cV3G0B;EU4G1B,0BA1F8B;ATmgBlC;;ASheA;EA4DM,4BV3GwB;EU4GxB,cVnHwB;AC2hB9B;;ASreA;EAgEM,yBChB2B;EDiB3B,cVvHwB;ACgiB9B;;AS1eA;;EAoEM,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;AT2atB;;ASjfA;EAwEI,gBAvG0B;EAwG1B,yBAvGmC;EAwGnC,cVhH8B;EUiH9B,qBAvG0B;ATohB9B;;ASxfA;EA8EM,cVpH4B;EUqH5B,0BAzGmC;ATuhBzC;;AS7fA;EAoFM,uBVjIyB;EUkIzB,yBAAyB;EACzB,cVhJuB;AC6jB7B;;ASngBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,cVrJqB;ACmkB7B;;ASzgBA;EA8FQ,yBAAyB;EACzB,cVzJqB;ACwkB7B;;AS9gBA;EAiGU,mDV9IqB;AC+jB/B;;ASlhBA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,cVhKqB;ACklB7B;;ASxhBA;;EAyGQ,uBVtJuB;EUuJvB,mBVvJuB;EUwJvB,gBAAgB;ATobxB;;AS/hBA;EA6GQ,yBVvKqB;EUwKrB,YV3JuB;ACilB/B;;ASpiBA;EAiHU,uBCjEuB;AVwfjC;;ASxiBA;;EAoHU,yBV9KmB;EU+KnB,yBAAyB;EACzB,gBAAgB;EAChB,YVpKqB;AC6lB/B;;AShjBA;EA0HU,gEAA4E;AT0btF;;ASpjBA;EA4HQ,6BAA6B;EAC7B,mBV1KuB;EU2KvB,YV3KuB;ACumB/B;;AS1jBA;EAmIU,uBVhLqB;EUiLrB,mBVjLqB;EUkLrB,cV/LmB;AC0nB7B;;AShkBA;EAwIY,4DAA8D;AT4b1E;;ASpkBA;EA8Ic,gEAA4E;AT0b1F;;ASxkBA;;EAiJU,6BAA6B;EAC7B,mBV/LqB;EUgMrB,gBAAgB;EAChB,YVjMqB;AC6nB/B;;AShlBA;EAsJQ,6BAA6B;EAC7B,qBVjNqB;EUkNrB,cVlNqB;ACgpB7B;;AStlBA;EA6JU,yBVvNmB;EUwNnB,YV3MqB;ACwoB/B;;AS3lBA;EAqKc,4DAA8D;AT0b5E;;AS/lBA;;EAwKU,6BAA6B;EAC7B,qBVnOmB;EUoOnB,gBAAgB;EAChB,cVrOmB;ACiqB7B;;ASvmBA;EAoFM,yBV9IuB;EU+IvB,yBAAyB;EACzB,YVnIyB;AC0pB/B;;AS7mBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,YVxIuB;ACgqB/B;;ASnnBA;EA8FQ,yBAAyB;EACzB,YV5IuB;ACqqB/B;;ASxnBA;EAiGU,gDV3JmB;ACsrB7B;;AS5nBA;EAoGQ,uBCpDyB;EDqDzB,yBAAyB;EACzB,YVnJuB;AC+qB/B;;ASloBA;;EAyGQ,yBVnKqB;EUoKrB,qBVpKqB;EUqKrB,gBAAgB;AT8hBxB;;ASzoBA;EA6GQ,uBV1JuB;EU2JvB,cVxKqB;ACwsB7B;;AS9oBA;EAiHU,yBCjEuB;AVkmBjC;;ASlpBA;;EAoHU,uBVjKqB;EUkKrB,yBAAyB;EACzB,gBAAgB;EAChB,cVjLmB;ACotB7B;;AS1pBA;EA0HU,4DAA4E;AToiBtF;;AS9pBA;EA4HQ,6BAA6B;EAC7B,qBVvLqB;EUwLrB,cVxLqB;AC8tB7B;;ASpqBA;EAmIU,yBV7LmB;EU8LnB,qBV9LmB;EU+LnB,YVlLqB;ACutB/B;;AS1qBA;EAwIY,gEAA8D;ATsiB1E;;AS9qBA;EA8Ic,4DAA4E;AToiB1F;;ASlrBA;;EAiJU,6BAA6B;EAC7B,qBV5MmB;EU6MnB,gBAAgB;EAChB,cV9MmB;ACovB7B;;AS1rBA;EAsJQ,6BAA6B;EAC7B,mBVpMuB;EUqMvB,YVrMuB;AC6uB/B;;AShsBA;EA6JU,uBV1MqB;EU2MrB,cVxNmB;AC+vB7B;;ASrsBA;EAqKc,gEAA8D;AToiB5E;;ASzsBA;;EAwKU,6BAA6B;EAC7B,mBVtNqB;EUuNrB,gBAAgB;EAChB,YVxNqB;AC8vB/B;;ASjtBA;EAoFM,4BVnIwB;EUoIxB,yBAAyB;EACzB,yBClEe;AVmsBrB;;ASvtBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,yBCvEa;AVysBrB;;AS7tBA;EA8FQ,yBAAyB;EACzB,yBC3Ea;AV8sBrB;;ASluBA;EAiGU,mDVhJoB;ACqxB9B;;AStuBA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,yBClFa;AVwtBrB;;AS5uBA;;EAyGQ,4BVxJsB;EUyJtB,wBVzJsB;EU0JtB,gBAAgB;ATwoBxB;;ASnvBA;EA6GQ,oCCzFa;ED0Fb,iBV7JsB;ACuyB9B;;ASxvBA;EAiHU,oCCjEuB;AV4sBjC;;AS5vBA;;EAoHU,oCChGW;EDiGX,yBAAyB;EACzB,gBAAgB;EAChB,iBVtKoB;ACmzB9B;;ASpwBA;EA0HU,sFAA4E;AT8oBtF;;ASxwBA;EA4HQ,6BAA6B;EAC7B,wBV5KsB;EU6KtB,iBV7KsB;AC6zB9B;;AS9wBA;EAmIU,4BVlLoB;EUmLpB,wBVnLoB;EUoLpB,yBCjHW;AVgwBrB;;ASpxBA;EAwIY,sEAA8D;ATgpB1E;;ASxxBA;EA8Ic,sFAA4E;AT8oB1F;;AS5xBA;;EAiJU,6BAA6B;EAC7B,wBVjMoB;EUkMpB,gBAAgB;EAChB,iBVnMoB;ACm1B9B;;ASpyBA;EAsJQ,6BAA6B;EAC7B,gCCnIa;EDoIb,yBCpIa;AVsxBrB;;AS1yBA;EA6JU,oCCzIW;ED0IX,iBV7MoB;AC81B9B;;AS/yBA;EAqKc,sEAA8D;AT8oB5E;;ASnzBA;;EAwKU,6BAA6B;EAC7B,gCCrJW;EDsJX,gBAAgB;EAChB,yBCvJW;AVuyBrB;;AS3zBA;EAoFM,yBV1IwB;EU2IxB,yBAAyB;EACzB,WChEU;AV2yBhB;;ASj0BA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVizBhB;;ASv0BA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVszBhB;;AS50BA;EAiGU,gDVvJoB;ACs4B9B;;ASh1BA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVg0BhB;;ASt1BA;;EAyGQ,yBV/JsB;EUgKtB,qBVhKsB;EUiKtB,gBAAgB;ATkvBxB;;AS71BA;EA6GQ,sBCvFQ;EDwFR,cVpKsB;ACw5B9B;;ASl2BA;EAiHU,yBCjEuB;AVszBjC;;ASt2BA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7KoB;ACo6B9B;;AS92BA;EA0HU,0DAA4E;ATwvBtF;;ASl3BA;EA4HQ,6BAA6B;EAC7B,qBVnLsB;EUoLtB,cVpLsB;AC86B9B;;ASx3BA;EAmIU,yBVzLoB;EU0LpB,qBV1LoB;EU2LpB,WC/GM;AVw2BhB;;AS93BA;EAwIY,gEAA8D;AT0vB1E;;ASl4BA;EA8Ic,0DAA4E;ATwvB1F;;ASt4BA;;EAiJU,6BAA6B;EAC7B,qBVxMoB;EUyMpB,gBAAgB;EAChB,cV1MoB;ACo8B9B;;AS94BA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV83BhB;;ASp5BA;EA6JU,sBCvIM;EDwIN,cVpNoB;AC+8B9B;;ASz5BA;EAqKc,gEAA8D;ATwvB5E;;AS75BA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV+4BhB;;ASr6BA;EAoFM,yBV5H4B;EU6H5B,yBAAyB;EACzB,WChEU;AVq5BhB;;AS36BA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AV25BhB;;ASj7BA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVg6BhB;;ASt7BA;EAiGU,iDVzIwB;ACk+BlC;;AS17BA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AV06BhB;;ASh8BA;;EAyGQ,yBVjJ0B;EUkJ1B,qBVlJ0B;EUmJ1B,gBAAgB;AT41BxB;;ASv8BA;EA6GQ,sBCvFQ;EDwFR,cVtJ0B;ACo/BlC;;AS58BA;EAiHU,yBCjEuB;AVg6BjC;;ASh9BA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV/JwB;ACggClC;;ASx9BA;EA0HU,0DAA4E;ATk2BtF;;AS59BA;EA4HQ,6BAA6B;EAC7B,qBVrK0B;EUsK1B,cVtK0B;AC0gClC;;ASl+BA;EAmIU,yBV3KwB;EU4KxB,qBV5KwB;EU6KxB,WC/GM;AVk9BhB;;ASx+BA;EAwIY,gEAA8D;ATo2B1E;;AS5+BA;EA8Ic,0DAA4E;ATk2B1F;;ASh/BA;;EAiJU,6BAA6B;EAC7B,qBV1LwB;EU2LxB,gBAAgB;EAChB,cV5LwB;ACgiClC;;ASx/BA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVw+BhB;;AS9/BA;EA6JU,sBCvIM;EDwIN,cVtMwB;AC2iClC;;ASngCA;EAqKc,gEAA8D;ATk2B5E;;ASvgCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVy/BhB;;AS/gCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV++BrE;;ASphCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVq/BrE;;AS1hCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AV2/BrE;;AShiCA;EAoFM,yBV1H4B;EU2H5B,yBAAyB;EACzB,WChEU;AVghChB;;AStiCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVshChB;;AS5iCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AV2hChB;;ASjjCA;EAiGU,iDVvIwB;AC2lClC;;ASrjCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVqiChB;;AS3jCA;;EAyGQ,yBV/I0B;EUgJ1B,qBVhJ0B;EUiJ1B,gBAAgB;ATu9BxB;;ASlkCA;EA6GQ,sBCvFQ;EDwFR,cVpJ0B;AC6mClC;;ASvkCA;EAiHU,yBCjEuB;AV2hCjC;;AS3kCA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7JwB;ACynClC;;ASnlCA;EA0HU,0DAA4E;AT69BtF;;ASvlCA;EA4HQ,6BAA6B;EAC7B,qBVnK0B;EUoK1B,cVpK0B;ACmoClC;;AS7lCA;EAmIU,yBVzKwB;EU0KxB,qBV1KwB;EU2KxB,WC/GM;AV6kChB;;ASnmCA;EAwIY,gEAA8D;AT+9B1E;;ASvmCA;EA8Ic,0DAA4E;AT69B1F;;AS3mCA;;EAiJU,6BAA6B;EAC7B,qBVxLwB;EUyLxB,gBAAgB;EAChB,cV1LwB;ACypClC;;ASnnCA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVmmChB;;ASznCA;EA6JU,sBCvIM;EDwIN,cVpMwB;ACoqClC;;AS9nCA;EAqKc,gEAA8D;AT69B5E;;ASloCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVonChB;;AS1oCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV0mCrE;;AS/oCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVgnCrE;;ASrpCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVsnCrE;;AS3pCA;EAoFM,yBV3H4B;EU4H5B,yBAAyB;EACzB,WChEU;AV2oChB;;ASjqCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVipChB;;ASvqCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVspChB;;AS5qCA;EAiGU,kDVxIwB;ACutClC;;AShrCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVgqChB;;AStrCA;;EAyGQ,yBVhJ0B;EUiJ1B,qBVjJ0B;EUkJ1B,gBAAgB;ATklCxB;;AS7rCA;EA6GQ,sBCvFQ;EDwFR,cVrJ0B;ACyuClC;;ASlsCA;EAiHU,yBCjEuB;AVspCjC;;AStsCA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV9JwB;ACqvClC;;AS9sCA;EA0HU,0DAA4E;ATwlCtF;;ASltCA;EA4HQ,6BAA6B;EAC7B,qBVpK0B;EUqK1B,cVrK0B;AC+vClC;;ASxtCA;EAmIU,yBV1KwB;EU2KxB,qBV3KwB;EU4KxB,WC/GM;AVwsChB;;AS9tCA;EAwIY,gEAA8D;AT0lC1E;;ASluCA;EA8Ic,0DAA4E;ATwlC1F;;AStuCA;;EAiJU,6BAA6B;EAC7B,qBVzLwB;EU0LxB,gBAAgB;EAChB,cV3LwB;ACqxClC;;AS9uCA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV8tChB;;ASpvCA;EA6JU,sBCvIM;EDwIN,cVrMwB;ACgyClC;;ASzvCA;EAqKc,gEAA8D;ATwlC5E;;AS7vCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV+uChB;;ASrwCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVquCrE;;AS1wCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AV2uCrE;;AShxCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVivCrE;;AStxCA;EAoFM,yBV7H4B;EU8H5B,yBAAyB;EACzB,WChEU;AVswChB;;AS5xCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AV4wChB;;ASlyCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVixChB;;ASvyCA;EAiGU,kDV1IwB;ACo1ClC;;AS3yCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AV2xChB;;ASjzCA;;EAyGQ,yBVlJ0B;EUmJ1B,qBVnJ0B;EUoJ1B,gBAAgB;AT6sCxB;;ASxzCA;EA6GQ,sBCvFQ;EDwFR,cVvJ0B;ACs2ClC;;AS7zCA;EAiHU,yBCjEuB;AVixCjC;;ASj0CA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cVhKwB;ACk3ClC;;ASz0CA;EA0HU,0DAA4E;ATmtCtF;;AS70CA;EA4HQ,6BAA6B;EAC7B,qBVtK0B;EUuK1B,cVvK0B;AC43ClC;;ASn1CA;EAmIU,yBV5KwB;EU6KxB,qBV7KwB;EU8KxB,WC/GM;AVm0ChB;;ASz1CA;EAwIY,gEAA8D;ATqtC1E;;AS71CA;EA8Ic,0DAA4E;ATmtC1F;;ASj2CA;;EAiJU,6BAA6B;EAC7B,qBV3LwB;EU4LxB,gBAAgB;EAChB,cV7LwB;ACk5ClC;;ASz2CA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVy1ChB;;AS/2CA;EA6JU,sBCvIM;EDwIN,cVvMwB;AC65ClC;;ASp3CA;EAqKc,gEAA8D;ATmtC5E;;ASx3CA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV02ChB;;ASh4CA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVg2CrE;;ASr4CA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVs2CrE;;AS34CA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AV42CrE;;ASj5CA;EAoFM,yBV9H4B;EU+H5B,yBAAyB;EACzB,yBClEe;AVm4CrB;;ASv5CA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,yBCvEa;AVy4CrB;;AS75CA;EA8FQ,yBAAyB;EACzB,yBC3Ea;AV84CrB;;ASl6CA;EAiGU,mDV3IwB;ACg9ClC;;ASt6CA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,yBClFa;AVw5CrB;;AS56CA;;EAyGQ,yBVnJ0B;EUoJ1B,qBVpJ0B;EUqJ1B,gBAAgB;ATw0CxB;;ASn7CA;EA6GQ,oCCzFa;ED0Fb,cVxJ0B;ACk+ClC;;ASx7CA;EAiHU,oCCjEuB;AV44CjC;;AS57CA;;EAoHU,oCChGW;EDiGX,yBAAyB;EACzB,gBAAgB;EAChB,cVjKwB;AC8+ClC;;ASp8CA;EA0HU,sFAA4E;AT80CtF;;ASx8CA;EA4HQ,6BAA6B;EAC7B,qBVvK0B;EUwK1B,cVxK0B;ACw/ClC;;AS98CA;EAmIU,yBV7KwB;EU8KxB,qBV9KwB;EU+KxB,yBCjHW;AVg8CrB;;ASp9CA;EAwIY,gEAA8D;ATg1C1E;;ASx9CA;EA8Ic,sFAA4E;AT80C1F;;AS59CA;;EAiJU,6BAA6B;EAC7B,qBV5LwB;EU6LxB,gBAAgB;EAChB,cV9LwB;AC8gDlC;;ASp+CA;EAsJQ,6BAA6B;EAC7B,gCCnIa;EDoIb,yBCpIa;AVs9CrB;;AS1+CA;EA6JU,oCCzIW;ED0IX,cVxMwB;ACyhDlC;;AS/+CA;EAqKc,gEAA8D;AT80C5E;;ASn/CA;;EAwKU,6BAA6B;EAC7B,gCCrJW;EDsJX,gBAAgB;EAChB,yBCvJW;AVu+CrB;;AS3/CA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV29CrE;;AShgDA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVi+CrE;;AStgDA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVu+CrE;;AS5gDA;EAoFM,yBVxH2B;EUyH3B,yBAAyB;EACzB,WChEU;AV4/ChB;;ASlhDA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVkgDhB;;ASxhDA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVugDhB;;AS7hDA;EAiGU,kDVrIuB;ACqkDjC;;ASjiDA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVihDhB;;ASviDA;;EAyGQ,yBV7IyB;EU8IzB,qBV9IyB;EU+IzB,gBAAgB;ATm8CxB;;AS9iDA;EA6GQ,sBCvFQ;EDwFR,cVlJyB;ACulDjC;;ASnjDA;EAiHU,yBCjEuB;AVugDjC;;ASvjDA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV3JuB;ACmmDjC;;AS/jDA;EA0HU,0DAA4E;ATy8CtF;;ASnkDA;EA4HQ,6BAA6B;EAC7B,qBVjKyB;EUkKzB,cVlKyB;AC6mDjC;;ASzkDA;EAmIU,yBVvKuB;EUwKvB,qBVxKuB;EUyKvB,WC/GM;AVyjDhB;;AS/kDA;EAwIY,gEAA8D;AT28C1E;;ASnlDA;EA8Ic,0DAA4E;ATy8C1F;;ASvlDA;;EAiJU,6BAA6B;EAC7B,qBVtLuB;EUuLvB,gBAAgB;EAChB,cVxLuB;ACmoDjC;;AS/lDA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV+kDhB;;ASrmDA;EA6JU,sBCvIM;EDwIN,cVlMuB;AC8oDjC;;AS1mDA;EAqKc,gEAA8D;ATy8C5E;;AS9mDA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVgmDhB;;AStnDA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVslDrE;;AS3nDA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AV4lDrE;;ASjoDA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVkmDrE;;ASvoDA;EARE,kBVdc;ACiqDhB;;ASrpDE;EACE,kBVkBc;ACsoDlB;;AS/oDA;EANE,eVjBW;AC0qDb;;ASnpDA;EAJE,kBVpBc;AC+qDhB;;ASvpDA;EAFE,iBVvBa;ACorDf;;AS3pDA;;EAyMI,uBVtP2B;EUuP3B,qBV5P0B;EU6P1B,gBAjOyB;EAkOzB,YAjOyB;ATwrD7B;;ASnqDA;EA8MI,aAAa;EACb,WAAW;ATy9Cf;;ASxqDA;EAiNI,6BAA6B;EAC7B,oBAAoB;AT29CxB;;AS7qDA;ERnDE,kBAAkB;EAKhB,6BAAmC;EACnC,4BAAkC;EQmQhC,6BAA6B;AT89CnC;;ASprDA;EAwNI,4BVvQ0B;EUwQ1B,qBV3Q0B;EU4Q1B,cV9Q0B;EU+Q1B,gBAAgB;EAChB,oBAAoB;ATg+CxB;;AS5rDA;EA8NI,qBVlNmB;EUmNnB,gCAA0D;EAC1D,iCAA2D;ATk+C/D;;ASh+CA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;ATm+C7B;;ASv+CA;EAMI,qBAAqB;ATq+CzB;;AS3+CA;ER1GI,oBQkHwC;ATu+C5C;;AS/+CA;EAUI,sBAAsB;ATy+C1B;;ASn/CA;EAYI,mBAAmB;AT2+CvB;;ASv/CA;EA1OE,kBVdc;ACmvDhB;;ASvuDE;EACE,kBVkBc;ACwtDlB;;AS//CA;EAtOE,kBVpBc;AC6vDhB;;ASngDA;EApOE,iBVvBa;ACkwDf;;ASvgDA;EA0BQ,4BAA4B;EAC5B,yBAAyB;ATi/CjC;;AS5gDA;EA6BQ,6BAA6B;EAC7B,0BAA0B;ERxI9B,kBQyIwC;ATm/C5C;;ASlhDA;ER1GI,eQ2IqC;ATq/CzC;;ASthDA;EAoCQ,UAAU;ATs/ClB;;AS1hDA;EA0CQ,UAAU;ATo/ClB;;AS9hDA;EA4CU,UAAU;ATs/CpB;;ASliDA;EA8CQ,YAAY;EACZ,cAAc;ATw/CtB;;ASviDA;EAiDI,uBAAuB;AT0/C3B;;AS3iDA;EAoDQ,oBAAoB;EACpB,qBAAqB;AT2/C7B;;AShjDA;EAuDI,yBAAyB;AT6/C7B;;ASpjDA;EA0DQ,oBAAoB;EACpB,qBAAqB;AT8/C7B;;ACzvDE;EQiQM;IACE,oBAlTyD;ET8yDjE;ES1/CM;;IAEE,qBAtT0F;ETkzDlG;ESjgDM;IACE,kBV1TM;EC6zDd;ESpgDM;IACE,eV3TG;ECi0DX;AACF;;ACrwDE;EQ6PM;IACE,qBAlTyL;ET8zDjM;ES1gDM;;IAEE,kBV9TM;EC00Dd;ESjhDM;IACE,eV3TG;EC80DX;ESphDM;IACE,kBV5TM;ECk1Dd;AACF;;AWl3DA;EACE,YAAY;EACZ,cAAc;EACd,kBAAkB;EAClB,WAAW;AXq3Db;;AWz3DA;EAMI,0BAA0B;EAC1B,kBZyCM;EYxCN,mBZwCM;EYvCN,WAAW;AXu3Df;;AC/wDE;EUjHF;IAWI,gBAAuC;EX03DzC;AACF;;AC3wDI;EU3HJ;IAcM,iBAAqE;EX63DzE;AACF;;AClwDI;EU1IJ;IAiBM,iBAAiE;EXg4DrE;AACF;;AClxDI;EUhIJ;IAoBM,iBAAqE;EXm4DzE;AACF;;ACzwDI;EU/IJ;IAuBM,iBAAiE;EXs4DrE;AACF;;AY34DA;EAII,kBAAkB;AZ24DtB;;AY/4DA;;;;;;;EAcM,kBAhC2B;AZ26DjC;;AYz5DA;;;;;;EAqBI,cbvC0B;EawC1B,gBbHiB;EaIjB,kBA3C+B;AZw7DnC;;AYp6DA;EAyBI,cAAc;EACd,oBAAoB;AZ+4DxB;;AYz6DA;EA4BM,eAAe;AZi5DrB;;AY76DA;EA8BI,iBAAiB;EACjB,uBAAuB;AZm5D3B;;AYl7DA;EAiCM,oBAAoB;AZq5D1B;;AYt7DA;EAmCI,gBAAgB;EAChB,uBAAuB;AZu5D3B;;AY37DA;EAsCM,oBAAoB;AZy5D1B;;AY/7DA;EAwCI,iBAAiB;EACjB,oBAAoB;AZ25DxB;;AYp8DA;EA2CI,kBAAkB;EAClB,uBAAuB;AZ65D3B;;AYz8DA;EA8CI,cAAc;EACd,kBAAkB;AZ+5DtB;;AY98DA;EAiDI,4Bb5D0B;EEuK1B,8BF1K0B;EaiE1B,qBAjEqC;AZk+DzC;;AYp9DA;EAqDI,4BAA4B;EXuG5B,gBWtGmC;EACnC,eAAe;AZm6DnB;;AY19DA;EAyDM,wBAAwB;AZq6D9B;;AY99DA;EA2DQ,4BAA4B;AZu6DpC;;AYl+DA;EA6DQ,4BAA4B;AZy6DpC;;AYt+DA;EA+DQ,4BAA4B;AZ26DpC;;AY1+DA;EAiEQ,4BAA4B;AZ66DpC;;AY9+DA;EAmEI,wBAAwB;EXyFxB,gBWxFmC;EACnC,eAAe;AZ+6DnB;;AYp/DA;EAuEM,uBAAuB;EACvB,iBAAiB;AZi7DvB;;AYz/DA;EA0EQ,uBAAuB;AZm7D/B;;AY7/DA;EX4JI,gBWhFmC;AZq7DvC;;AYjgEA;EA8EI,gBAAgB;EAChB,iBAAiB;EACjB,kBAAkB;AZu7DtB;;AYvgEA;EAkFM,eAAe;AZy7DrB;;AY3gEA;EAoFM,kBAAkB;AZ27DxB;;AY/gEA;EAsFM,qBAAqB;AZ67D3B;;AYnhEA;EAwFM,kBAAkB;AZ+7DxB;;AYvhEA;EX2CE,iCAAiC;EWgD/B,gBAAgB;EAChB,qBAxG8B;EAyG9B,gBAAgB;EAChB,iBAAiB;AZi8DrB;;AY/hEA;;EAiGI,cAAc;AZm8DlB;;AYpiEA;EAmGI,WAAW;AZq8Df;;AYxiEA;;EAsGM,yBbpHwB;EaqHxB,qBAhHmC;EAiHnC,qBAhHmC;EAiHnC,mBAAmB;AZu8DzB;;AYhjEA;EA2GM,cb7HwB;ACskE9B;;AYpjEA;EA6GQ,mBAAmB;AZ28D3B;;AYxjEA;;EAiHQ,qBAvHsC;EAwHtC,cbpIsB;ACglE9B;;AY9jEA;;EAsHQ,qBAzHsC;EA0HtC,cbzIsB;ACslE9B;;AYpkEA;;EA6HY,sBAjI4C;AZ6kExD;;AYzkEA;EAgIM,aAAa;AZ68DnB;;AY7kEA;EAmII,kBbrHY;ACmkEhB;;AYjlEA;EAqII,ebxHS;ACwkEb;;AYrlEA;EAuII,kBb3HY;AC6kEhB;;AYzlEA;EAyII,iBb9HW;ACklEf;;Aa/mEA;EACE,mBAAmB;EACnB,oBAAoB;EACpB,uBAAuB;EACvB,cAVsB;EAWtB,aAXsB;Ab6nExB;;AavnEA;EAQI,YAbwB;EAcxB,WAdwB;AbioE5B;;Aa5nEA;EAWI,YAfyB;EAgBzB,WAhByB;AbqoE7B;;AajoEA;EAcI,YAjBwB;EAkBxB,WAlBwB;AbyoE5B;;AarnEA;EACE,uBAAuB;EACvB,cAAc;EACd,oBAAoB;EACpB,eAAe;EACf,mBA5BsB;EA6BtB,mBAAmB;AbwnErB;;Aa9nEA;EAQI,YAAY;EACZ,cAAc;Ab0nElB;;AanoEA;EAYQ,oBA/BkB;Ab0pE1B;;AavoEA;EAiBQ,mBApCkB;Ab8pE1B;;AatnEA;EACE,aAAa;AbynEf;;AclqEA;EACE,cAAc;EACd,kBAAkB;AdqqEpB;;AcvqEA;EAII,cAAc;EACd,YAAY;EACZ,WAAW;AduqEf;;Ac7qEA;EAQM,qBf4DiB;AC6mEvB;;AcjrEA;EAUI,WAAW;Ad2qEf;;AcrrEA;;;;;;;;;;;;;;;;;EA+BM,YAAY;EACZ,WAAW;Ad0qEjB;;Ac1sEA;EAmCI,iBAAiB;Ad2qErB;;Ac9sEA;EAqCI,gBAAgB;Ad6qEpB;;AcltEA;EAuCI,gBAAgB;Ad+qEpB;;ActtEA;EAyCI,qBAAqB;AdirEzB;;Ac1tEA;EA2CI,gBAAgB;AdmrEpB;;Ac9tEA;EA6CI,mBAAmB;AdqrEvB;;AcluEA;EA+CI,gBAAgB;AdurEpB;;ActuEA;EAiDI,qBAAqB;AdyrEzB;;Ac1uEA;EAmDI,iBAAiB;Ad2rErB;;Ac9uEA;EAqDI,sBAAsB;Ad6rE1B;;AclvEA;EAuDI,iBAAiB;Ad+rErB;;ActvEA;EAyDI,sBAAsB;AdisE1B;;Ac1vEA;EA2DI,sBAAsB;AdmsE1B;;Ac9vEA;EA6DI,iBAAiB;AdqsErB;;AclwEA;EA+DI,iBAAiB;AdusErB;;ActwEA;EAmEM,YAAwB;EACxB,WAAuB;AdusE7B;;Ac3wEA;EAmEM,YAAwB;EACxB,WAAuB;Ad4sE7B;;AchxEA;EAmEM,YAAwB;EACxB,WAAuB;AditE7B;;AcrxEA;EAmEM,YAAwB;EACxB,WAAuB;AdstE7B;;Ac1xEA;EAmEM,YAAwB;EACxB,WAAuB;Ad2tE7B;;Ac/xEA;EAmEM,YAAwB;EACxB,WAAuB;AdguE7B;;AcpyEA;EAmEM,aAAwB;EACxB,YAAuB;AdquE7B;;AelyEA;EAEE,4BhBA4B;EgBC5B,kBhBwDU;EgBvDV,kBAAkB;EAEhB,sCAXoD;Af8yExD;;AezyEA;EAUI,mBAAmB;EACnB,0BAA0B;AfmyE9B;;Ae9yEA;EAaI,mBAAmB;AfqyEvB;;AelzEA;;EAgBI,iBhBZ2B;ACmzE/B;;AevzEA;EAkBI,uBAAuB;AfyyE3B;;Ae3zEA;EdiLI,ac7J4B;EAC5B,kBAAkB;EAClB,WAAW;Af2yEf;;Aej0EA;;;EA0BI,mBAAmB;Af6yEvB;;Aev0EA;EAgCM,uBhB5ByB;EgB6BzB,chB1CuB;ACq1E7B;;Ae50EA;EAgCM,yBhBzCuB;EgB0CvB,YhB7ByB;AC60E/B;;Aej1EA;EAgCM,4BhB9BwB;EgB+BxB,yBLoCe;AVixErB;;Aet1EA;EAgCM,yBhBrCwB;EgBsCxB,WLsCU;AVoxEhB;;Ae31EA;EAgCM,yBhBvB4B;EgBwB5B,WLsCU;AVyxEhB;;Aeh2EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AV+wErE;;Aer2EA;EAgCM,yBhBrB4B;EgBsB5B,WLsCU;AVmyEhB;;Ae12EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVyxErE;;Ae/2EA;EAgCM,yBhBtB4B;EgBuB5B,WLsCU;AV6yEhB;;Aep3EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVmyErE;;Aez3EA;EAgCM,yBhBxB4B;EgByB5B,WLsCU;AVuzEhB;;Ae93EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AV6yErE;;Aen4EA;EAgCM,yBhBzB4B;EgB0B5B,yBLoCe;AVm0ErB;;Aex4EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVuzErE;;Ae74EA;EAgCM,yBhBnB2B;EgBoB3B,WLsCU;AV20EhB;;Ael5EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVi0ErE;;AgBx5EA;EAEE,qBAAqB;EACrB,wBAAwB;EACxB,YAAY;EACZ,qBjByDqB;EiBxDrB,cAAc;EACd,YjBoBW;EiBnBX,gBAAgB;EAChB,UAAU;EACV,WAAW;AhB05Eb;;AgBp6EA;EAYI,yBjBX2B;ACu6E/B;;AgBx6EA;EAcI,yBjBjB0B;AC+6E9B;;AgB56EA;EAgBI,yBjBnB0B;ACm7E9B;;AgBh7EA;EAkBI,yBjBrB0B;EiBsB1B,YAAY;AhBk6EhB;;AgBr7EA;EAyBQ,uBjBpBuB;ACo7E/B;;AgBz7EA;EA2BQ,uBjBtBuB;ACw7E/B;;AgB77EA;EA6BQ,uBjBxBuB;AC47E/B;;AgBj8EA;EA+BQ,mEAA2F;AhBs6EnG;;AgBr8EA;EAyBQ,yBjBjCqB;ACi9E7B;;AgBz8EA;EA2BQ,yBjBnCqB;ACq9E7B;;AgB78EA;EA6BQ,yBjBrCqB;ACy9E7B;;AgBj9EA;EA+BQ,qEAA2F;AhBs7EnG;;AgBr9EA;EAyBQ,4BjBtBsB;ACs9E9B;;AgBz9EA;EA2BQ,4BjBxBsB;AC09E9B;;AgB79EA;EA6BQ,4BjB1BsB;AC89E9B;;AgBj+EA;EA+BQ,wEAA2F;AhBs8EnG;;AgBr+EA;EAyBQ,yBjB7BsB;AC6+E9B;;AgBz+EA;EA2BQ,yBjB/BsB;ACi/E9B;;AgB7+EA;EA6BQ,yBjBjCsB;ACq/E9B;;AgBj/EA;EA+BQ,qEAA2F;AhBs9EnG;;AgBr/EA;EAyBQ,yBjBf0B;AC++ElC;;AgBz/EA;EA2BQ,yBjBjB0B;ACm/ElC;;AgB7/EA;EA6BQ,yBjBnB0B;ACu/ElC;;AgBjgFA;EA+BQ,qEAA2F;AhBs+EnG;;AgBrgFA;EAyBQ,yBjBb0B;AC6/ElC;;AgBzgFA;EA2BQ,yBjBf0B;ACigFlC;;AgB7gFA;EA6BQ,yBjBjB0B;ACqgFlC;;AgBjhFA;EA+BQ,qEAA2F;AhBs/EnG;;AgBrhFA;EAyBQ,yBjBd0B;AC8gFlC;;AgBzhFA;EA2BQ,yBjBhB0B;ACkhFlC;;AgB7hFA;EA6BQ,yBjBlB0B;ACshFlC;;AgBjiFA;EA+BQ,qEAA2F;AhBsgFnG;;AgBriFA;EAyBQ,yBjBhB0B;ACgiFlC;;AgBziFA;EA2BQ,yBjBlB0B;ACoiFlC;;AgB7iFA;EA6BQ,yBjBpB0B;ACwiFlC;;AgBjjFA;EA+BQ,qEAA2F;AhBshFnG;;AgBrjFA;EAyBQ,yBjBjB0B;ACijFlC;;AgBzjFA;EA2BQ,yBjBnB0B;ACqjFlC;;AgB7jFA;EA6BQ,yBjBrB0B;ACyjFlC;;AgBjkFA;EA+BQ,qEAA2F;AhBsiFnG;;AgBrkFA;EAyBQ,yBjBXyB;AC2jFjC;;AgBzkFA;EA2BQ,yBjBbyB;AC+jFjC;;AgB7kFA;EA6BQ,yBjBfyB;ACmkFjC;;AgBjlFA;EA+BQ,qEAA2F;AhBsjFnG;;AgBrlFA;EAkCI,gCAtCkC;UAsClC,wBAtCkC;EAuClC,2CAAmC;UAAnC,mCAAmC;EACnC,yCAAiC;UAAjC,iCAAiC;EACjC,yCAAiC;UAAjC,iCAAiC;EACjC,yBjBrC2B;EiBsC3B,qEAA0F;EAC1F,6BAA6B;EAC7B,4BAA4B;EAC5B,0BAA0B;AhBujF9B;;AgBjmFA;EA4CM,6BAA6B;AhByjFnC;;AgBrmFA;EA8CM,6BAA6B;AhB2jFnC;;AgBzmFA;EAgDM,oBAAoB;AhB6jF1B;;AgB7mFA;EAoDI,ejBxBY;ACqlFhB;;AgBjnFA;EAsDI,ejB5BY;AC2lFhB;;AgBrnFA;EAwDI,cjB/BW;ACgmFf;;AgB/jFA;EACE;IACE,2BAA2B;EhBkkF7B;EgBjkFA;IACE,4BAA4B;EhBmkF9B;AACF;;AgBxkFA;EACE;IACE,2BAA2B;EhBkkF7B;EgBjkFA;IACE,4BAA4B;EhBmkF9B;AACF;;AiB9mFA;EAEE,uBlBjB6B;EkBkB7B,clB3B4B;AC2oF9B;;AiBnnFA;;EAMI,yBlB1B0B;EkB2B1B,qBA/B6B;EAgC7B,qBA/B6B;EAgC7B,mBAAmB;AjBknFvB;;AiB3nFA;;EAeQ,uBlB9BuB;EkB+BvB,mBlB/BuB;EkBgCvB,clB7CqB;AC8pF7B;;AiBloFA;;EAeQ,yBlB3CqB;EkB4CrB,qBlB5CqB;EkB6CrB,YlBhCuB;ACwpF/B;;AiBzoFA;;EAeQ,4BlBhCsB;EkBiCtB,wBlBjCsB;EkBkCtB,yBPiCa;AV8lFrB;;AiBhpFA;;EAeQ,yBlBvCsB;EkBwCtB,qBlBxCsB;EkByCtB,WPmCQ;AVmmFhB;;AiBvpFA;;EAeQ,yBlBzB0B;EkB0B1B,qBlB1B0B;EkB2B1B,WPmCQ;AV0mFhB;;AiB9pFA;;EAeQ,yBlBvB0B;EkBwB1B,qBlBxB0B;EkByB1B,WPmCQ;AVinFhB;;AiBrqFA;;EAeQ,yBlBxB0B;EkByB1B,qBlBzB0B;EkB0B1B,WPmCQ;AVwnFhB;;AiB5qFA;;EAeQ,yBlB1B0B;EkB2B1B,qBlB3B0B;EkB4B1B,WPmCQ;AV+nFhB;;AiBnrFA;;EAeQ,yBlB3B0B;EkB4B1B,qBlB5B0B;EkB6B1B,yBPiCa;AVwoFrB;;AiB1rFA;;EAeQ,yBlBrByB;EkBsBzB,qBlBtByB;EkBuBzB,WPmCQ;AV6oFhB;;AiBjsFA;;EAoBM,mBAAmB;EACnB,SAAS;AjBkrFf;;AiBvsFA;;EAuBM,yBlBjC4B;EkBkC5B,WP4BU;AVypFhB;;AiB7sFA;;;;EA2BQ,mBAAmB;AjByrF3B;;AiBptFA;;EA6BM,sBAAsB;AjB4rF5B;;AiBztFA;EA+BI,clBvD0B;ACqvF9B;;AiB7tFA;EAiCM,gBAtDsB;AjBsvF5B;;AiBjuFA;EAoCM,yBlB9C4B;EkB+C5B,WPeU;AVkrFhB;;AiBtuFA;;EAwCQ,mBAAmB;AjBmsF3B;;AiB3uFA;;EA2CQ,kBPSQ;EORR,mBAAmB;AjBqsF3B;;AiBjvFA;EA8CI,6BA5DqC;AjBmwFzC;;AiBrvFA;;EAiDM,qBApEgC;EAqEhC,clB1EwB;ACmxF9B;;AiB3vFA;EAoDI,6BAhEqC;AjB2wFzC;;AiB/vFA;;EAuDM,qBAxEgC;EAyEhC,clBhFwB;AC6xF9B;;AiBrwFA;EA0DI,6BAvEqC;AjBsxFzC;;AiBzwFA;;EA+DU,sBAAsB;AjB+sFhC;;AiB9wFA;;EAoEM,iBAAiB;AjB+sFvB;;AiBnxFA;;EAyEU,wBAAwB;AjB+sFlC;;AiBxxFA;EA2EI,WAAW;AjBitFf;;AiB5xFA;EAgFU,yBlBhGoB;ACgzF9B;;AiBhyFA;EAqFY,yBlBrGkB;ACozF9B;;AiBpyFA;EAuFc,4BlBxGgB;ACyzF9B;;AiBxyFA;;EA2FM,qBAAqB;AjBktF3B;;AiB7yFA;EAgGU,yBlBhHoB;ACi0F9B;;AiB/sFA;EhB7DE,iCAAiC;EgBgEjC,cAAc;EACd,kBAAkB;EAClB,eAAe;AjBitFjB;;AkB70FA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;AlBg1F7B;;AkBp1FA;EAMI,qBAAqB;AlBk1FzB;;AkBx1FA;EjB2KI,oBiBnKwC;AlBo1F5C;;AkB51FA;EAUI,sBAAsB;AlBs1F1B;;AkBh2FA;EAYI,mBAAmB;AlBw1FvB;;AkBp2FA;EAgBM,enBYO;AC40Fb;;AkBx2FA;EAmBM,kBnBQU;ACi1FhB;;AkB52FA;EAqBI,uBAAuB;AlB21F3B;;AkBh3FA;EAuBM,qBAAqB;EACrB,oBAAoB;AlB61F1B;;AkBr3FA;EA0BI,yBAAyB;AlB+1F7B;;AkBz3FA;EA6BQ,mBAAmB;AlBg2F3B;;AkB73FA;EA+BQ,eAAe;AlBk2FvB;;AkBj4FA;EjB2KI,eiBzImC;AlBm2FvC;;AkBr4FA;EjB2KI,ciBvIqC;EAE/B,yBAAyB;EACzB,4BAA4B;AlBo2FtC;;AkB34FA;EA6CU,0BAA0B;EAC1B,6BAA6B;AlBk2FvC;;AkB71FA;EACE,mBAAmB;EACnB,4BnBjD4B;EmBkD5B,kBnBOU;EmBNV,cnBzD4B;EmB0D5B,oBAAoB;EACpB,kBnB5Bc;EmB6Bd,WAAW;EACX,uBAAuB;EACvB,gBAAgB;EAChB,oBAAoB;EACpB,qBAAqB;EACrB,mBAAmB;AlBg2FrB;;AkB52FA;EjBwHI,oBiB1GuC;EjB0GvC,uBiBzGyC;AlBk2F7C;;AkBj3FA;EAqBM,uBnBlEyB;EmBmEzB,cnBhFuB;ACg7F7B;;AkBt3FA;EAqBM,yBnB/EuB;EmBgFvB,YnBnEyB;ACw6F/B;;AkB33FA;EAqBM,4BnBpEwB;EmBqExB,yBRFe;AV42FrB;;AkBh4FA;EAqBM,yBnB3EwB;EmB4ExB,WRAU;AV+2FhB;;AkBr4FA;EAqBM,yBnB7D4B;EmB8D5B,WRAU;AVo3FhB;;AkB14FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV02FrE;;AkB/4FA;EAqBM,yBnB3D4B;EmB4D5B,WRAU;AV83FhB;;AkBp5FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVo3FrE;;AkBz5FA;EAqBM,yBnB5D4B;EmB6D5B,WRAU;AVw4FhB;;AkB95FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV83FrE;;AkBn6FA;EAqBM,yBnB9D4B;EmB+D5B,WRAU;AVk5FhB;;AkBx6FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVw4FrE;;AkB76FA;EAqBM,yBnB/D4B;EmBgE5B,yBRFe;AV85FrB;;AkBl7FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVk5FrE;;AkBv7FA;EAqBM,yBnBzD2B;EmB0D3B,WRAU;AVs6FhB;;AkB57FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV45FrE;;AkBj8FA;EAgCI,kBnBtDY;AC29FhB;;AkBr8FA;EAkCI,enBzDS;ACg+Fb;;AkBz8FA;EAoCI,kBnB5DY;ACq+FhB;;AkB78FA;EjBwHI,qBiBjF0C;EjBiF1C,sBiBhF0C;AlB06F9C;;AkBl9FA;EjBwHI,qBiB9E0C;EjB8E1C,sBiB7E0C;AlB46F9C;;AkBv9FA;EjBwHI,qBiB3E0C;EjB2E1C,sBiB1E0C;AlB86F9C;;AkB59FA;EjBwHI,gBiB/KmB;EAyGnB,UAAU;EACV,kBAAkB;EAClB,UAAU;AlB+6Fd;;AkBn+FA;EAuDM,8BAA8B;EAC9B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;AlBg7FrC;;AkB9+FA;EAgEM,WAAW;EACX,UAAU;AlBk7FhB;;AkBn/FA;EAmEM,WAAW;EACX,UAAU;AlBo7FhB;;AkBx/FA;EAuEM,yBAAmD;AlBq7FzD;;AkB5/FA;EAyEM,yBAAoD;AlBu7F1D;;AkBhgGA;EA2EI,qBnB/DmB;ACw/FvB;;AkBv7FA;EAEI,0BAA0B;AlBy7F9B;;AmB/iGA;;EAGE,sBAAsB;AnBijGxB;;AmBpjGA;;;;EAMI,oBAAoB;AnBqjGxB;;AmB3jGA;;EAQI,iBApBmB;AnB4kGvB;;AmBhkGA;;EAUI,iBArBmB;AnBglGvB;;AmBrkGA;;EAYI,sBAAsB;AnB8jG1B;;AmB5jGA;EACE,cpB9B4B;EoBiC5B,epBLW;EoBMX,gBpBGmB;EoBFnB,kBAnCuB;AnBgmGzB;;AmBnkGA;EAQI,cApCwB;EAqCxB,oBApCyB;AnBmmG7B;;AmBxkGA;EAWI,oBA3B+B;AnB4lGnC;;AmB5kGA;EAgBM,epBnBO;ACmlGb;;AmBhlGA;EAgBM,iBpBlBS;ACslGf;;AmBplGA;EAgBM,epBjBO;ACylGb;;AmBxlGA;EAgBM,iBpBhBS;AC4lGf;;AmB5lGA;EAgBM,kBpBfU;AC+lGhB;;AmBhmGA;EAgBM,epBdO;ACkmGb;;AmBpmGA;EAgBM,kBpBbU;ACqmGhB;;AmBtlGA;EACE,cpB/C4B;EoBkD5B,kBpBrBc;EoBsBd,gBpBjBiB;EoBkBjB,iBA3CyB;AnBkoG3B;;AmB7lGA;EAQI,cpBvD0B;EoBwD1B,gBpBnBiB;AC4mGrB;;AmBlmGA;EAWI,oBA7C+B;AnBwoGnC;;AmBtmGA;EAgBM,epBrCO;AC+nGb;;AmB1mGA;EAgBM,iBpBpCS;ACkoGf;;AmB9mGA;EAgBM,epBnCO;ACqoGb;;AmBlnGA;EAgBM,iBpBlCS;ACwoGf;;AmBtnGA;EAgBM,kBpBjCU;AC2oGhB;;AmB1nGA;EAgBM,epBhCO;AC8oGb;;AmB9nGA;EAgBM,kBpB/BU;ACipGhB;;AoB/qGA;EACE,cAAc;EACd,eAAe;EACf,mBAAmB;EACnB,kBAAkB;EAClB,yBAAyB;ApBkrG3B;;AoB7qGA;EACE,mBAAmB;EACnB,4BrBP4B;EqBQ5B,qBrBmDqB;EqBlDrB,oBAAoB;EACpB,kBrBac;EqBZd,WAAW;EACX,uBAAuB;EACvB,oBAAoB;EACpB,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;EAClB,mBAAmB;ApBgrGrB;;AqB9sGA,eAAA;AC0DA;EAxBE,uBvBnB6B;EuBoB7B,qBvBzB4B;EuB0B5B,kBvBkCU;EuBjCV,cvB/B4B;ACgtG9B;;AC9oGI;EqBjCA,4BvBjC0B;ACotG9B;;AClpGI;EqBjCA,4BvBjC0B;ACwtG9B;;ACtpGI;EqBjCA,4BvBjC0B;AC4tG9B;;AC1pGI;EqBjCA,4BvBjC0B;ACguG9B;;AsB9rGE;EAEE,qBvBjC0B;ACiuG9B;;AsB/rGE;EAIE,qBvBzB8B;EuB0B9B,iDvB1B8B;ACytGlC;;AsB9rGE;;;;;EAEE,4BvBtC0B;EuBuC1B,wBvBvC0B;EuBwC1B,gBAAgB;EAChB,cvB9C0B;ACkvG9B;;AClrGI;;;;;EqBhBE,+BvBhDwB;AC0vG9B;;AC1rGI;;;;;EqBhBE,+BvBhDwB;ACkwG9B;;AClsGI;;;;;EqBhBE,+BvBhDwB;AC0wG9B;;AC1sGI;;;;;EqBhBE,+BvBhDwB;ACkxG9B;;AuBpxGA;EAEE,2DxBN2B;EwBO3B,eAAe;EACf,WAAW;AvBsxGb;;AuBrxGE;EACE,gBAAgB;AvBwxGpB;;AuBpxGI;EACE,mBxBFyB;ACyxG/B;;AuBxxGK;EAMG,mDxBPuB;AC6xG/B;;AuB5xGI;EACE,qBxBfuB;AC8yG7B;;AuBhyGK;EAMG,gDxBpBqB;ACkzG7B;;AuBpyGI;EACE,wBxBJwB;AC2yG9B;;AuBxyGK;EAMG,mDxBTsB;AC+yG9B;;AuB5yGI;EACE,qBxBXwB;AC0zG9B;;AuBhzGK;EAMG,gDxBhBsB;AC8zG9B;;AuBpzGI;EACE,qBxBG4B;ACozGlC;;AuBxzGK;EAMG,iDxBF0B;ACwzGlC;;AuB5zGI;EACE,qBxBK4B;AC0zGlC;;AuBh0GK;EAMG,iDxBA0B;AC8zGlC;;AuBp0GI;EACE,qBxBI4B;ACm0GlC;;AuBx0GK;EAMG,kDxBD0B;ACu0GlC;;AuB50GI;EACE,qBxBE4B;AC60GlC;;AuBh1GK;EAMG,kDxBH0B;ACi1GlC;;AuBp1GI;EACE,qBxBC4B;ACs1GlC;;AuBx1GK;EAMG,mDxBJ0B;AC01GlC;;AuB51GI;EACE,qBxBO2B;ACw1GjC;;AuBh2GK;EAMG,kDxBEyB;AC41GjC;;AuB51GE;EzBmBA,kBC0BgB;EDzBhB,kBCNc;ACm1GhB;;AuB/1GE;EzBoBA,kBCVc;ACy1GhB;;AuBj2GE;EzBoBA,iBCba;AC81Gf;;AuBl2GE;EACE,cAAc;EACd,WAAW;AvBq2Gf;;AuBp2GE;EACE,eAAe;EACf,WAAW;AvBu2Gf;;AuBr2GA;EAGI,qBxB+BmB;EwB9BnB,gDAA4D;EAC5D,iDAA6D;AvBs2GjE;;AuB32GA;EAOI,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;EACf,gBAAgB;AvBw2GpB;;AuBt2GA;EAEE,cAAc;EACd,eAAe;EACf,eAAe;EACf,2BzB7CkE;EyB8ClE,gBAAgB;AvBw2GlB;;AuB92GA;EAQI,gBA1DsB;EA2DtB,eA1DqB;AvBo6GzB;;AuBn3GA;EAWI,eAAe;AvB42GnB;;AuBv3GA;EAcI,YAAY;AvB62GhB;;AwB96GA;EACE,eAAe;EACf,qBAAqB;EACrB,iBAAiB;EACjB,kBAAkB;AxBi7GpB;;AwBh7GE;EACE,eAAe;AxBm7GnB;;AwBl7GE;EACE,czBF0B;ACu7G9B;;AwBp7GE;;;;;EAGE,czBJ0B;EyBK1B,mBAAmB;AxBy7GvB;;AwBp7GA;EvBkKI,kBuB/JqC;AxBq7GzC;;AyBx8GA;EACE,qBAAqB;EACrB,eAAe;EACf,kBAAkB;EAClB,mBAAmB;AzB28GrB;;AyB/8GA;EAMI,a3BDkB;AE88GtB;;AyBn9GA;EAUM,qB1BU4B;EEsK9B,cwB/K+B;EAC7B,UAAU;AzB68GhB;;AyBz9GA;EAeM,qB1BuDiB;EE4GnB,iBwBlKsC;AzB88G1C;;AyB99GA;EAmBI,eAAe;EACf,cAAc;EACd,cAAc;EACd,eAAe;EACf,aAAa;AzB+8GjB;;AyBt+GA;EAyBM,aAAa;AzBi9GnB;;AyB1+GA;;EA4BM,wB1BjBwB;ACo+G9B;;AyB/+GA;ExBkLI,oBwBpJwC;AzBq9G5C;;AyBn/GA;EAgCM,YAAY;EACZ,UAAU;AzBu9GhB;;AyBx/GA;EAmCQ,kBAAkB;AzBy9G1B;;AyB5/GA;EAuCM,qB1BnCwB;AC4/G9B;;AyBhgHA;EA6CQ,mB1BhCuB;ACu/G/B;;AyBpgHA;EA+CQ,mB1BlCuB;AC2/G/B;;AyBxgHA;EAkDU,qBfwDuB;AVk6GjC;;AyB5gHA;EAuDU,mD1B1CqB;ACmgH/B;;AyBhhHA;EA6CQ,qB1B7CqB;ACohH7B;;AyBphHA;EA+CQ,qB1B/CqB;ACwhH7B;;AyBxhHA;EAkDU,mBfwDuB;AVk7GjC;;AyB5hHA;EAuDU,gD1BvDmB;ACgiH7B;;AyBhiHA;EA6CQ,wB1BlCsB;ACyhH9B;;AyBpiHA;EA+CQ,wB1BpCsB;AC6hH9B;;AyBxiHA;EAkDU,qBfwDuB;AVk8GjC;;AyB5iHA;EAuDU,mD1B5CoB;ACqiH9B;;AyBhjHA;EA6CQ,qB1BzCsB;ACgjH9B;;AyBpjHA;EA+CQ,qB1B3CsB;ACojH9B;;AyBxjHA;EAkDU,qBfwDuB;AVk9GjC;;AyB5jHA;EAuDU,gD1BnDoB;AC4jH9B;;AyBhkHA;EA6CQ,qB1B3B0B;ACkjHlC;;AyBpkHA;EA+CQ,qB1B7B0B;ACsjHlC;;AyBxkHA;EAkDU,qBfwDuB;AVk+GjC;;AyB5kHA;EAuDU,iD1BrCwB;AC8jHlC;;AyBhlHA;EA6CQ,qB1BzB0B;ACgkHlC;;AyBplHA;EA+CQ,qB1B3B0B;ACokHlC;;AyBxlHA;EAkDU,qBfwDuB;AVk/GjC;;AyB5lHA;EAuDU,iD1BnCwB;AC4kHlC;;AyBhmHA;EA6CQ,qB1B1B0B;ACilHlC;;AyBpmHA;EA+CQ,qB1B5B0B;ACqlHlC;;AyBxmHA;EAkDU,qBfwDuB;AVkgHjC;;AyB5mHA;EAuDU,kD1BpCwB;AC6lHlC;;AyBhnHA;EA6CQ,qB1B5B0B;ACmmHlC;;AyBpnHA;EA+CQ,qB1B9B0B;ACumHlC;;AyBxnHA;EAkDU,qBfwDuB;AVkhHjC;;AyB5nHA;EAuDU,kD1BtCwB;AC+mHlC;;AyBhoHA;EA6CQ,qB1B7B0B;AConHlC;;AyBpoHA;EA+CQ,qB1B/B0B;ACwnHlC;;AyBxoHA;EAkDU,qBfwDuB;AVkiHjC;;AyB5oHA;EAuDU,mD1BvCwB;ACgoHlC;;AyBhpHA;EA6CQ,qB1BvByB;AC8nHjC;;AyBppHA;EA+CQ,qB1BzByB;ACkoHjC;;AyBxpHA;EAkDU,qBfwDuB;AVkjHjC;;AyB5pHA;EAuDU,kD1BjCuB;AC0oHjC;;AyBhqHA;E3ByCE,kBC0BgB;EDzBhB,kBCNc;ACioHhB;;AyBrqHA;E3B4CE,kBCVc;ACuoHhB;;AyBzqHA;E3B8CE,iBCba;AC4oHf;;AyB7qHA;EAkEM,gCAA8C;EAC9C,YAAY;AzB+mHlB;;AyBlrHA;EAqEI,WAAW;AzBinHf;;AyBtrHA;EAuEM,WAAW;AzBmnHjB;;AyB1rHA;EA2EM,aAAa;EACb,kBAAkB;ExB8GpB,cwB7G+B;EAC7B,YAAY;EACZ,eAAe;AzBmnHrB;;AyBlsHA;EAiFM,kB1B7CU;ACkqHhB;;AyBtsHA;EAmFM,kB1BjDU;ACwqHhB;;AyB1sHA;EAqFM,iB1BpDS;AC6qHf;;A0BjsHA;EAEE,oBAAoB;EACpB,aAAa;EACb,2BAA2B;EAC3B,kBAAkB;A1BmsHpB;;A0BxsHA;EAYQ,uB3BZuB;E2BavB,yBAAyB;EACzB,c3B3BqB;AC2tH7B;;A0B9sHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,c3BjCmB;ACiuH7B;;A0BptHA;EAwBU,yBAAyB;EACzB,+C3BzBqB;E2B0BrB,c3BvCmB;ACuuH7B;;A0B1tHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,c3B7CmB;AC6uH7B;;A0BhuHA;EAYQ,yB3BzBqB;E2B0BrB,yBAAyB;EACzB,Y3BduB;ACsuH/B;;A0BtuHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,Y3BpBqB;AC4uH/B;;A0B5uHA;EAwBU,yBAAyB;EACzB,4C3BtCmB;E2BuCnB,Y3B1BqB;ACkvH/B;;A0BlvHA;EA8BU,uBhB+DuB;EgB9DvB,yBAAyB;EACzB,Y3BhCqB;ACwvH/B;;A0BxvHA;EAYQ,4B3BdsB;E2BetB,yBAAyB;EACzB,yBhBmDa;AV6rHrB;;A0B9vHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,yBhB6CW;AVmsHrB;;A0BpwHA;EAwBU,yBAAyB;EACzB,+C3B3BoB;E2B4BpB,yBhBuCW;AVysHrB;;A0B1wHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,yBhBiCW;AV+sHrB;;A0BhxHA;EAYQ,yB3BrBsB;E2BsBtB,yBAAyB;EACzB,WhBqDQ;AVmtHhB;;A0BtxHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVytHhB;;A0B5xHA;EAwBU,yBAAyB;EACzB,4C3BlCoB;E2BmCpB,WhByCM;AV+tHhB;;A0BlyHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVquHhB;;A0BxyHA;EAYQ,yB3BP0B;E2BQ1B,yBAAyB;EACzB,WhBqDQ;AV2uHhB;;A0B9yHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVivHhB;;A0BpzHA;EAwBU,yBAAyB;EACzB,6C3BpBwB;E2BqBxB,WhByCM;AVuvHhB;;A0B1zHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AV6vHhB;;A0Bh0HA;EAYQ,yB3BL0B;E2BM1B,yBAAyB;EACzB,WhBqDQ;AVmwHhB;;A0Bt0HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVywHhB;;A0B50HA;EAwBU,yBAAyB;EACzB,6C3BlBwB;E2BmBxB,WhByCM;AV+wHhB;;A0Bl1HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVqxHhB;;A0Bx1HA;EAYQ,yB3BN0B;E2BO1B,yBAAyB;EACzB,WhBqDQ;AV2xHhB;;A0B91HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AViyHhB;;A0Bp2HA;EAwBU,yBAAyB;EACzB,8C3BnBwB;E2BoBxB,WhByCM;AVuyHhB;;A0B12HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AV6yHhB;;A0Bh3HA;EAYQ,yB3BR0B;E2BS1B,yBAAyB;EACzB,WhBqDQ;AVmzHhB;;A0Bt3HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVyzHhB;;A0B53HA;EAwBU,yBAAyB;EACzB,8C3BrBwB;E2BsBxB,WhByCM;AV+zHhB;;A0Bl4HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVq0HhB;;A0Bx4HA;EAYQ,yB3BT0B;E2BU1B,yBAAyB;EACzB,yBhBmDa;AV60HrB;;A0B94HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,yBhB6CW;AVm1HrB;;A0Bp5HA;EAwBU,yBAAyB;EACzB,+C3BtBwB;E2BuBxB,yBhBuCW;AVy1HrB;;A0B15HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,yBhBiCW;AV+1HrB;;A0Bh6HA;EAYQ,yB3BHyB;E2BIzB,yBAAyB;EACzB,WhBqDQ;AVm2HhB;;A0Bt6HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVy2HhB;;A0B56HA;EAwBU,yBAAyB;EACzB,8C3BhBuB;E2BiBvB,WhByCM;AV+2HhB;;A0Bl7HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVq3HhB;;A0Bx7HA;EAmCI,kB3BZY;ACq6HhB;;A0B57HA;EAqCI,e3BfS;AC06Hb;;A0Bh8HA;EAuCI,kB3BlBY;AC+6HhB;;A0Bp8HA;EA0CQ,eAAe;A1B85HvB;;A0Bx8HA;EA4CI,iB3BxBW;ACw7Hf;;A0B58HA;EA+CQ,eAAe;A1Bi6HvB;;A0Bh9HA;EAmDM,6BAA6B;EAC7B,0BAA0B;A1Bi6HhC;;A0Br9HA;EAsDM,4BAA4B;EAC5B,yBAAyB;A1Bm6H/B;;A0B19HA;EA0DQ,kB3BHI;ACu6HZ;;A0B99HA;EA4DQ,aAAa;A1Bs6HrB;;A0Bl+HA;EA+DM,sBAAsB;A1Bu6H5B;;A0Bt+HA;EAiEM,sBAAsB;EACtB,YAAY;EACZ,gBAAgB;A1By6HtB;;A0B5+HA;EAqEM,uBAAuB;A1B26H7B;;A0Bh/HA;EAuEM,aAAa;EACb,YAAY;A1B66HlB;;A0Br/HA;EA0EQ,eAAe;A1B+6HvB;;A0Bz/HA;EA6EQ,eAAe;A1Bg7HvB;;A0B7/HA;EAgFQ,eAAe;A1Bi7HvB;;A0BjgIA;EAmFQ,eAAe;A1Bk7HvB;;A0BrgIA;EAsFQ,0BAA4C;A1Bm7HpD;;A0BzgIA;EAwFQ,0B3BjCI;E2BkCJ,uBAAuB;A1Bq7H/B;;A0B9gIA;EA2FI,uBAAuB;A1Bu7H3B;;A0BlhIA;EA8FM,WAAW;A1Bw7HjB;;A0BthIA;EAgGM,YAAY;EACZ,eAAe;A1B07HrB;;A0B3hIA;EAmGI,yBAAyB;A1B47H7B;;A0B/hIA;EAqGM,0BAA4C;A1B87HlD;;A0BniIA;EAuGM,0B3BhDM;E2BiDN,2BAA2B;EAC3B,SAAS;A1Bg8Hf;;A0B97HA;EACE,oBAAoB;EACpB,aAAa;EACb,eAAe;EACf,2BAA2B;EAC3B,gBAAgB;EAChB,kBAAkB;A1Bi8HpB;;A0Bv8HA;EASM,yBhBvB2B;EgBwB3B,c3B9HwB;ACgkI9B;;A0B58HA;EAYM,qBhB1B2B;AV89HjC;;A0Bh9HA;EAeM,yBhB7B2B;EgB8B3B,c3BpIwB;ACykI9B;;A0Br9HA;EAkBM,qBhBhC2B;AVu+HjC;;A0Br8HA;EACE,YAAY;EACZ,OAAO;EACP,UAAU;EACV,aAAa;EACb,kBAAkB;EAClB,MAAM;EACN,WAAW;A1Bw8Hb;;A0Bt8HA;;EAGE,qB3BhJ4B;E2BiJ5B,kB3BrFU;E2BsFV,cAAc;EACd,iBAAiB;EACjB,kBAAkB;EAClB,mBAAmB;A1Bw8HrB;;A0Bt8HA;EACE,4B3BrJ4B;E2BsJ5B,c3B5J4B;ACqmI9B;;A0Bv8HA;EACE,qB3B5J4B;E2B6J5B,mBA9J4B;EA+J5B,2BA9JoC;EA+JpC,cAAc;EACd,eA/JwB;EAgKxB,gBAAgB;EAChB,mBAAmB;EACnB,uBAAuB;A1B08HzB;;A0Bx8HA;EACE,mBAAmB;EACnB,aAAa;EACb,WAAW;EACX,uBAAuB;EzBCrB,mByBAmC;EACrC,UAAU;A1B28HZ;;A0Bj9HA;EAQI,eAAe;A1B68HnB;;A2B7nIA;EACE,c5BF4B;E4BG5B,cAAc;EACd,e5B2BW;E4B1BX,gB5BiCe;AC+lIjB;;A2BpoIA;EAMI,oBAAoB;A3BkoIxB;;A2BxoIA;EASI,kB5BsBY;AC6mIhB;;A2B5oIA;EAWI,kB5BkBY;ACmnIhB;;A2BhpIA;EAaI,iB5BeW;ACwnIf;;A2BroIA;EACE,cAAc;EACd,kB5Bcc;E4Bbd,mBAAmB;A3BwoIrB;;A2B3oIA;EAOM,Y5BdyB;ACspI/B;;A2B/oIA;EAOM,c5B3BuB;ACuqI7B;;A2BnpIA;EAOM,iB5BhBwB;ACgqI9B;;A2BvpIA;EAOM,c5BvBwB;AC2qI9B;;A2B3pIA;EAOM,c5BT4B;ACiqIlC;;A2B/pIA;EAOM,c5BP4B;ACmqIlC;;A2BnqIA;EAOM,c5BR4B;ACwqIlC;;A2BvqIA;EAOM,c5BV4B;AC8qIlC;;A2B3qIA;EAOM,c5BX4B;ACmrIlC;;A2B/qIA;EAOM,c5BL2B;ACirIjC;;A2BxqIA;EAEI,sBAAsB;A3B0qI1B;;A2B5qIA;EAKI,aAAa;EACb,2BAA2B;A3B2qI/B;;A2BjrIA;E1BmJI,kB0B1IwC;A3B4qI5C;;A2BrrIA;;;EAcU,gBAAgB;A3B6qI1B;;A2B3rIA;;;EAoBY,6BAA6B;EAC7B,0BAA0B;A3B6qItC;;A2BlsIA;;;EA8BY,4BAA4B;EAC5B,yBAAyB;A3B0qIrC;;A2BzsIA;;;;;EAyCY,UAAU;A3BwqItB;;A2BjtIA;;;;;;;;;EA8CY,UAAU;A3B+qItB;;A2B7tIA;;;;;;;;;EAgDc,UAAU;A3ByrIxB;;A2BzuIA;EAkDQ,YAAY;EACZ,cAAc;A3B2rItB;;A2B9uIA;EAqDM,uBAAuB;A3B6rI7B;;A2BlvIA;EAuDM,yBAAyB;A3B+rI/B;;A2BtvIA;EA0DQ,YAAY;EACZ,cAAc;A3BgsItB;;A2B3vIA;EA6DI,aAAa;EACb,2BAA2B;A3BksI/B;;A2BhwIA;EAgEM,cAAc;A3BosIpB;;A2BpwIA;EAkEQ,gBAAgB;E1BiFpB,qB0BhF2C;A3BssI/C;;A2BzwIA;EAqEQ,YAAY;EACZ,cAAc;A3BwsItB;;A2B9wIA;EAwEM,uBAAuB;A3B0sI7B;;A2BlxIA;EA0EM,yBAAyB;A3B4sI/B;;A2BtxIA;EA4EM,eAAe;A3B8sIrB;;A2B1xIA;EAgFU,sBAAsB;A3B8sIhC;;A2B9xIA;EAkFQ,uBAAuB;A3BgtI/B;;A2BlyIA;EAoFQ,gBAAgB;A3BktIxB;;AC7tIE;E0BzEF;IAuFM,aAAa;E3BotIjB;AACF;;A2BntIA;EAEI,kBAAkB;A3BqtItB;;AC3uIE;E0BoBF;IAII,qBAAqB;E3BwtIvB;AACF;;AC7uIE;E0BgBF;IAMI,aAAa;IACb,YAAY;IACZ,cAAc;I1BkDd,oB0BjDsC;IACtC,iBAAiB;E3B4tInB;E2BtuIF;IAYM,kB5BhGU;I4BiGV,oBAAoB;E3B6tIxB;E2B1uIF;IAeM,oBAAoB;E3B8tIxB;E2B7uIF;IAiBM,kB5BvGU;I4BwGV,oBAAoB;E3B+tIxB;E2BjvIF;IAoBM,iB5B3GS;I4B4GT,oBAAoB;E3BguIxB;AACF;;A2B/tIA;EAEI,gBAAgB;A3BiuIpB;;AC1wIE;E0BuCF;IAII,aAAa;IACb,aAAa;IACb,YAAY;IACZ,cAAc;E3BouIhB;E2B3uIF;IASM,gBAAgB;E3BquIpB;E2B9uIF;IAWM,cAAc;E3BsuIlB;E2BjvIF;IAaQ,YAAY;E3BuuIlB;E2BpvIF;I1BmCI,qB0BpB2C;E3BwuI7C;AACF;;A2BvuIA;EACE,sBAAsB;EACtB,WAAW;EACX,e5BhIW;E4BiIX,kBAAkB;EAClB,mBAAmB;A3B0uIrB;;A2B/uIA;;;EAaU,c5BxKoB;ACg5I9B;;A2BrvIA;;;EAeQ,kB5B3IQ;ACu3IhB;;A2B3vIA;;;EAiBQ,kB5B/IQ;AC+3IhB;;A2BjwIA;;;EAmBQ,iB5BlJO;ACs4If;;A2BvwIA;EAqBM,c5B7KwB;E4B8KxB,a7BjLgB;E6BkLhB,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,Y7BrLgB;E6BsLhB,UAAU;A3BsvIhB;;A2BjxIA;;EA+BM,mB7B1LgB;AEi7ItB;;A2BtxIA;EAiCM,OAAO;A3ByvIb;;A2B1xIA;;EAqCM,oB7BhMgB;AE07ItB;;A2B/xIA;EAuCM,QAAQ;A3B4vId;;A2BnyIA;EA2CM,6BAA6B;E1BjB/B,c0BkB+B;EAC7B,YAAY;EACZ,UAAU;A3B4vIhB;;A2B1yIA;EAgDM,kB5B5KU;AC06IhB;;A2B9yIA;EAkDM,kB5BhLU;ACg7IhB;;A2BlzIA;EAoDM,iB5BnLS;ACq7If;;A4Bx9IA,qBAAA;ACWA;EAGE,e9BuBW;E8BtBX,mBAAmB;A7B+8IrB;;A6Bn9IA;EAMI,mBAAmB;EACnB,c9BI8B;E8BH9B,aAAa;EACb,uBAAuB;EACvB,iBAduC;A7B+9I3C;;A6B39IA;EAYM,c9BjBwB;ACo+I9B;;A6B/9IA;EAcI,mBAAmB;EACnB,aAAa;A7Bq9IjB;;A6Bp+IA;E5ByKI,e4BxJoC;A7Bu9IxC;;A6Bx+IA;EAoBQ,c9BzBsB;E8B0BtB,eAAe;EACf,oBAAoB;A7Bw9I5B;;A6B9+IA;EAwBM,c9B1BwB;E8B2BxB,iBAAiB;A7B09IvB;;A6Bn/IA;;EA4BI,uBAAuB;EACvB,aAAa;EACb,eAAe;EACf,2BAA2B;A7B49I/B;;A6B3/IA;E5ByKI,mB4BvIuC;A7B69I3C;;A6B//IA;E5ByKI,kB4BrIuC;A7B+9I3C;;A6BngJA;;EAyCM,uBAAuB;A7B+9I7B;;A6BxgJA;;EA6CM,yBAAyB;A7Bg+I/B;;A6B7gJA;EAgDI,kB9BrBY;ACs/IhB;;A6BjhJA;EAkDI,kB9BzBY;AC4/IhB;;A6BrhJA;EAoDI,iB9B5BW;ACigJf;;A6BzhJA;EAwDM,iBAAiB;A7Bq+IvB;;A6B7hJA;EA2DM,iBAAiB;A7Bs+IvB;;A6BjiJA;EA8DM,iBAAiB;A7Bu+IvB;;A6BriJA;EAiEM,iBAAiB;A7Bw+IvB;;A8B9hJA;EACE,uB/BR6B;E+BS7B,sBAnBmB;EAoBnB,0F/BvB2B;E+BwB3B,c/BnB4B;E+BoB5B,eAAe;EACf,kBAAkB;A9BiiJpB;;A8B9hJE;EACE,+BA3BiB;EA4BjB,gCA5BiB;A9B6jJrB;;A8BhiJE;EACE,kCA9BiB;EA+BjB,mCA/BiB;A9BkkJrB;;A8BjiJA;EAEE,6BAjCwC;EAkCxC,oBAAoB;EACpB,kD/BxC2B;E+ByC3B,aAAa;A9BmiJf;;A8BjiJA;EACE,mBAAmB;EACnB,c/BzC4B;E+B0C5B,aAAa;EACb,YAAY;EACZ,gB/BNe;E+BOf,qBA1CgC;A9B8kJlC;;A8B1iJA;EAQI,uBAAuB;A9BsiJ3B;;A8BpiJA;E7BqBE,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,mBAAmB;EACnB,oBAAoB;EACpB,cAAc;EACd,SAAS;EACT,UAAU;E6B5BV,mBAAmB;EACnB,eAAe;EACf,aAAa;EACb,uBAAuB;EACvB,qBApDgC;A9BomJlC;;A8B9iJA;EACE,cAAc;EACd,kBAAkB;A9BijJpB;;A8BnjJA;EAKM,+BA/De;EAgEf,gCAhEe;A9BknJrB;;A8BxjJA;EASM,kCAnEe;EAoEf,mCApEe;A9BunJrB;;A8BjjJA;EAEE,6BAhEyC;EAiEzC,eAhE2B;A9BmnJ7B;;A8BjjJA;EAEE,6BAlEwC;EAmExC,6B/BxE6B;E+ByE7B,oBAAoB;EACpB,aAAa;A9BmjJf;;A8BjjJA;EACE,mBAAmB;EACnB,aAAa;EACb,aAAa;EACb,YAAY;EACZ,cAAc;EACd,uBAAuB;EACvB,gBA5E2B;A9BgoJ7B;;A8B3jJA;E7B6FI,+BFzK2B;AC2oJ/B;;A8BljJA;EAEI,qB/BtDkB;AC0mJtB;;A+BroJA;EACE,oBAAoB;EACpB,kBAAkB;EAClB,mBAAmB;A/BwoJrB;;A+B3oJA;EAOM,cAAc;A/BwoJpB;;A+B/oJA;EAUM,UAAU;EACV,QAAQ;A/ByoJd;;A+BppJA;EAcM,YAAY;EACZ,mBA9BuB;EA+BvB,oBAAoB;EACpB,SAAS;A/B0oJf;;A+BxoJA;EACE,aAAa;E9BmJX,O8BlJqB;EACvB,gBAzC6B;EA0C7B,gBAtC2B;EAuC3B,kBAAkB;EAClB,SAAS;EACT,WApCqB;A/B+qJvB;;A+BzoJA;EACE,uBhCnC6B;EgCoC7B,kBhCmBU;EgClBV,0FhClD2B;EgCmD3B,sBA9CsC;EA+CtC,mBA9CmC;A/B0rJrC;;Ae9qJgB;EgBqCd,chClD4B;EgCmD5B,cAAc;EACd,mBAAmB;EACnB,gBAAgB;EAChB,sBAAsB;EACtB,kBAAkB;A/B6oJpB;;A+B3oJA;;E9BoHI,mB8BlHmC;EACrC,mBAAmB;EACnB,mBAAmB;EACnB,WAAW;A/B8oJb;;A+BnpJA;;EAOI,4BhC1D0B;EgC2D1B,chCtEyB;ACutJ7B;;A+BzpJA;;EAUI,yBhCpD8B;EgCqD9B,WrBOY;AV6oJhB;;A+BlpJA;EACE,yBhCnE6B;EgCoE7B,YAAY;EACZ,cAAc;EACd,WAAW;EACX,gBAAgB;A/BqpJlB;;AgCnuJA;EAEE,mBAAmB;EACnB,8BAA8B;AhCquJhC;;AgCxuJA;EAKI,kBjC6DQ;AC0qJZ;;AgC5uJA;EAOI,qBAAqB;EACrB,mBAAmB;AhCyuJvB;;AgCjvJA;EAWI,aAAa;AhC0uJjB;;AgCrvJA;;EAcM,aAAa;AhC4uJnB;;AgC1vJA;EAgBM,aAAa;AhC8uJnB;;AgC9vJA;EAmBQ,gBAAgB;E/B6JpB,qB+BlLuC;AhCqwJ3C;;AgCnwJA;EAsBQ,YAAY;AhCivJpB;;ACjqJE;E+BtGF;IAyBI,aAAa;EhCmvJf;EgC5wJF;IA4BQ,YAAY;EhCmvJlB;AACF;;AgClvJA;EACE,mBAAmB;EACnB,aAAa;EACb,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,uBAAuB;AhCqvJzB;;AgC3vJA;;EASI,gBAAgB;AhCuvJpB;;AC5rJE;E+BpEF;IAaM,sBA7CqC;EhCqyJzC;AACF;;AgCvvJA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AhC0vJhB;;AgC9vJA;;EAQM,YAAY;AhC2vJlB;;AC1sJE;E+BzDF;;I/BmII,qB+BlLuC;EhCwzJzC;AACF;;AgC5vJA;EACE,mBAAmB;EACnB,2BAA2B;AhC+vJ7B;;AC1tJE;E+BvCF;IAMM,kBAAkB;EhCgwJtB;AACF;;AC5tJE;E+B3CF;IAQI,aAAa;EhCowJf;AACF;;AgCnwJA;EACE,mBAAmB;EACnB,yBAAyB;AhCswJ3B;;ACvuJE;E+BjCF;IAKI,aAAa;EhCwwJf;AACF;;AiC50JA;EACE,uBAAuB;EACvB,aAAa;EACb,mBAAmB;AjC+0JrB;;AiCl1JA;EAKI,sBAV2B;AjC21J/B;;AiCt1JA;EAOI,8ClCR0B;EkCS1B,aAAa;EACb,oBAb2B;AjCg2J/B;;AiC51JA;;EAYM,qBAfgC;AjCo2JtC;;AiCj2JA;EAcM,mBAhBwB;AjCu2J9B;;AiCr2JA;EAgBQ,kBAlBsB;AjC22J9B;;AiCz2JA;EAkBI,8ClCnB0B;EkCoB1B,gBA1BgB;EA2BhB,iBA3BgB;AjCs3JpB;;AiC/2JA;EAwBM,kBA9BsB;EA+BtB,mBA/BsB;AjC03J5B;;AiCz1JA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AjC41JhB;;AiC11JA;EhCwII,kBgChLgB;AjCs4JpB;;AiC31JA;EhCqII,iBgChLgB;AjC04JpB;;AiC51JA;EACE,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,mBAAmB;AjC+1JrB;;AC/yJE;EgCpDF;IAQI,gBAAgB;EjCg2JlB;AACF;;AkCv4JA;EACE,enCgBW;AC03Jb;;AkC34JA;EAII,kBnCcY;AC63JhB;;AkC/4JA;EAMI,kBnCUY;ACm4JhB;;AkCn5JA;EAQI,iBnCOW;ACw4Jf;;AkC74JA;EACE,iBArB0B;AlCq6J5B;;AkCj5JA;EAGI,kBnCoCc;EmCnCd,cnC3B0B;EmC4B1B,cAAc;EACd,qBAzBiC;AlC26JrC;;AkCx5JA;EAQM,4BnCzBwB;EmC0BxB,cnCjCwB;ACq7J9B;;AkC75JA;EAYM,yBnCpB4B;EmCqB5B,WxBuCU;AV82JhB;;AkCl6JA;EjCsJI,8BF1K0B;EmCqCxB,cAnC0B;EjCwK5B,oBiCvKkC;AlCy7JtC;;AkCp5JA;EACE,cnC3C4B;EmC4C5B,iBApC2B;EAqC3B,qBApC+B;EAqC/B,yBAAyB;AlCu5J3B;;AkC35JA;EAMI,eAtCoB;AlC+7JxB;;AkC/5JA;EAQI,kBAxCoB;AlCm8JxB;;AmC97JA;EAEE,4BpCZ4B;EoCa5B,kBpC4CU;EoC3CV,epCUW;ACs7Jb;;AmCp8JA;EAMI,mBAAmB;AnCk8JvB;;AmCx8JA;EAQI,mBAAmB;EACnB,0BAA0B;AnCo8J9B;;AmC78JA;EAYI,kBpCGY;ACk8JhB;;AmCj9JA;EAcI,kBpCDY;ACw8JhB;;AmCr9JA;EAgBI,iBpCJW;AC68Jf;;AmCz9JA;EAsCM,uBAH+C;AnC07JrD;;AmC79JA;EAwCQ,uBpChDuB;EoCiDvB,cpC9DqB;ACu/J7B;;AmCl+JA;EA2CQ,mBpCnDuB;AC8+J/B;;AmCt+JA;EAsCM,yBAH+C;AnCu8JrD;;AmC1+JA;EAwCQ,yBpC7DqB;EoC8DrB,YpCjDuB;ACu/J/B;;AmC/+JA;EA2CQ,qBpChEqB;ACwgK7B;;AmCn/JA;EAsCM,yBAH+C;AnCo9JrD;;AmCv/JA;EAwCQ,4BpClDsB;EoCmDtB,yBzBgBa;AVm8JrB;;AmC5/JA;EA2CQ,wBpCrDsB;AC0gK9B;;AmChgKA;EAsCM,yBAH+C;AnCi+JrD;;AmCpgKA;EAwCQ,yBpCzDsB;EoC0DtB,WzBkBQ;AV88JhB;;AmCzgKA;EA2CQ,qBpC5DsB;AC8hK9B;;AmC7gKA;EAsCM,yBzB4B0C;AV+8JhD;;AmCjhKA;EAwCQ,yBpC3C0B;EoC4C1B,WzBkBQ;AV29JhB;;AmCthKA;EA2CQ,qBpC9C0B;EoC+C1B,czB8B6D;AVi9JrE;;AmC3hKA;EAsCM,yBzB4B0C;AV69JhD;;AmC/hKA;EAwCQ,yBpCzC0B;EoC0C1B,WzBkBQ;AVy+JhB;;AmCpiKA;EA2CQ,qBpC5C0B;EoC6C1B,czB8B6D;AV+9JrE;;AmCziKA;EAsCM,yBzB4B0C;AV2+JhD;;AmC7iKA;EAwCQ,yBpC1C0B;EoC2C1B,WzBkBQ;AVu/JhB;;AmCljKA;EA2CQ,qBpC7C0B;EoC8C1B,czB8B6D;AV6+JrE;;AmCvjKA;EAsCM,yBzB4B0C;AVy/JhD;;AmC3jKA;EAwCQ,yBpC5C0B;EoC6C1B,WzBkBQ;AVqgKhB;;AmChkKA;EA2CQ,qBpC/C0B;EoCgD1B,czB8B6D;AV2/JrE;;AmCrkKA;EAsCM,yBzB4B0C;AVugKhD;;AmCzkKA;EAwCQ,yBpC7C0B;EoC8C1B,yBzBgBa;AVqhKrB;;AmC9kKA;EA2CQ,qBpChD0B;EoCiD1B,czB8B6D;AVygKrE;;AmCnlKA;EAsCM,yBzB4B0C;AVqhKhD;;AmCvlKA;EAwCQ,yBpCvCyB;EoCwCzB,WzBkBQ;AViiKhB;;AmC5lKA;EA2CQ,qBpC1CyB;EoC2CzB,czB8B6D;AVuhKrE;;AmCnjKA;EACE,mBAAmB;EACnB,yBpChE4B;EoCiE5B,0BAAgE;EAChE,WzBSc;EyBRd,aAAa;EACb,gBpC/Be;EoCgCf,8BAA8B;EAC9B,iBAAiB;EACjB,mBAtEiC;EAuEjC,kBAAkB;AnCsjKpB;;AmChkKA;EAYI,YAAY;EACZ,cAAc;ElCkGd,mBkCjGsC;AnCwjK1C;;AmCtkKA;EAgBI,eAjEgC;EAkEhC,yBAAyB;EACzB,0BAA0B;AnC0jK9B;;AmCxjKA;EACE,qBpChF4B;EoCiF5B,kBpCrBU;EoCsBV,mBAAmB;EACnB,uBAjFmC;EAkFnC,cpCvF4B;EoCwF5B,qBAjFiC;AnC4oKnC;;AmCjkKA;;EASI,uBpCnF2B;ACgpK/B;;AmCtkKA;EAWI,6BAlFgD;AnCipKpD;;AoCjoKA;EAEE,mBAAmB;EACnB,aAAa;EACb,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,eAAe;EACf,WAxCU;ApC2qKZ;;AoC3oKA;EAWI,aAAa;ApCooKjB;;AoCloKA;EAEE,wCrC/C2B;ACmrK7B;;AoCloKA;;EAEE,cA9CgC;EA+ChC,+BAA0D;EAC1D,cAAc;EACd,kBAAkB;EAClB,WAAW;ApCqoKb;;ACpmKE;EmCvCF;;IASI,cAAc;IACd,8BAA0D;IAC1D,YAxDuB;EpCgsKzB;AACF;;AoCvoKA;EAEE,gBAAgB;EAChB,YAxD2B;EAyD3B,eAAe;EnCwHb,WmChLoB;EA0DtB,SAzDoB;EA0DpB,WA5D2B;ApCqsK7B;;AoCvoKA;EACE,aAAa;EACb,sBAAsB;EACtB,8BAAgD;EAChD,gBAAgB;EAChB,uBAAuB;ApC0oKzB;;AoCxoKA;;EAEE,mBAAmB;EACnB,4BrCtE4B;EqCuE5B,aAAa;EACb,cAAc;EACd,2BAA2B;EAC3B,aApE4B;EAqE5B,kBAAkB;ApC2oKpB;;AoCzoKA;EACE,gCrCjF4B;EqCkF5B,2BrCrBgB;EqCsBhB,4BrCtBgB;ACkqKlB;;AoC1oKA;EACE,crC1F4B;EqC2F5B,YAAY;EACZ,cAAc;EACd,iBrChEa;EqCiEb,cA7E8B;ApC0tKhC;;AoC3oKA;EACE,8BrChCgB;EqCiChB,+BrCjCgB;EqCkChB,6BrC/F4B;AC6uK9B;;AoCjpKA;EnC8EI,mBmCxEuC;ApC+oK3C;;AoC7oKA;EnC3CE,iCAAiC;EmC6CjC,uBrCjG6B;EqCkG7B,YAAY;EACZ,cAAc;EACd,cAAc;EACd,aAtF4B;ApCsuK9B;;AqC1sKA;EACE,uBtC5C6B;EsC6C7B,mBAvDqB;EAwDrB,kBAAkB;EAClB,WAtDW;ArCmwKb;;AqCjtKA;EASM,uBtCpDyB;EsCqDzB,ctClEuB;AC8wK7B;;AqCttKA;;EAcU,ctCtEmB;ACmxK7B;;AqC3tKA;;;;EAoBY,yB3B8BqB;E2B7BrB,ctC7EiB;AC2xK7B;;AqCnuKA;EAwBY,qBtChFiB;AC+xK7B;;AqCvuKA;EA0BQ,ctClFqB;ACmyK7B;;AC3sKE;EoChCF;;;;IAgCY,ctCxFiB;EC2yK3B;EqCnvKF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,ctC/Fe;ECwzK3B;EqChwKF;;IA0Cc,qBtClGe;EC4zK3B;EqCpwKF;;;IA8CU,yB3BIuB;I2BHvB,ctCvGmB;ECk0K3B;EqC1wKF;IAmDc,uBtC9FiB;IsC+FjB,ctC5Ge;ECs0K3B;AACF;;AqC/wKA;EASM,yBtCjEuB;EsCkEvB,YtCrDyB;AC+zK/B;;AqCpxKA;;EAcU,YtCzDqB;ACo0K/B;;AqCzxKA;;;;EAoBY,uB3B8BqB;E2B7BrB,YtChEmB;AC40K/B;;AqCjyKA;EAwBY,mBtCnEmB;ACg1K/B;;AqCryKA;EA0BQ,YtCrEuB;ACo1K/B;;ACzwKE;EoChCF;;;;IAgCY,YtC3EmB;EC41K7B;EqCjzKF;;;;;;;;;;IAsCc,uB3BYmB;I2BXnB,YtClFiB;ECy2K7B;EqC9zKF;;IA0Cc,mBtCrFiB;EC62K7B;EqCl0KF;;;IA8CU,uB3BIuB;I2BHvB,YtC1FqB;ECm3K7B;EqCx0KF;IAmDc,yBtC3Ge;IsC4Gf,YtC/FiB;ECu3K7B;AACF;;AqC70KA;EASM,4BtCtDwB;EsCuDxB,yB3BYe;AV4zKrB;;AqCl1KA;;EAcU,yB3BQW;AVi0KrB;;AqCv1KA;;;;EAoBY,yB3B8BqB;E2B7BrB,yB3BCS;AVy0KrB;;AqC/1KA;EAwBY,gC3BFS;AV60KrB;;AqCn2KA;EA0BQ,yB3BJa;AVi1KrB;;ACv0KE;EoChCF;;;;IAgCY,yB3BVS;EVy1KnB;EqC/2KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,yB3BjBO;EVs2KnB;EqC53KF;;IA0Cc,gC3BpBO;EV02KnB;EqCh4KF;;;IA8CU,yB3BIuB;I2BHvB,yB3BzBW;EVg3KnB;EqCt4KF;IAmDc,4BtChGgB;IsCiGhB,yB3B9BO;EVo3KnB;AACF;;AqC34KA;EASM,yBtC7DwB;EsC8DxB,W3BcU;AVw3KhB;;AqCh5KA;;EAcU,W3BUM;AV63KhB;;AqCr5KA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVq4KhB;;AqC75KA;EAwBY,kB3BAI;AVy4KhB;;AqCj6KA;EA0BQ,W3BFQ;AV64KhB;;ACr4KE;EoChCF;;;;IAgCY,W3BRI;EVq5Kd;EqC76KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVk6Kd;EqC17KF;;IA0Cc,kB3BlBE;EVs6Kd;EqC97KF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EV46Kd;EqCp8KF;IAmDc,yBtCvGgB;IsCwGhB,W3B5BE;EVg7Kd;AACF;;AqCz8KA;EASM,yBtC/C4B;EsCgD5B,W3BcU;AVs7KhB;;AqC98KA;;EAcU,W3BUM;AV27KhB;;AqCn9KA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVm8KhB;;AqC39KA;EAwBY,kB3BAI;AVu8KhB;;AqC/9KA;EA0BQ,W3BFQ;AV28KhB;;ACn8KE;EoChCF;;;;IAgCY,W3BRI;EVm9Kd;EqC3+KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVg+Kd;EqCx/KF;;IA0Cc,kB3BlBE;EVo+Kd;EqC5/KF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EV0+Kd;EqClgLF;IAmDc,yBtCzFoB;IsC0FpB,W3B5BE;EV8+Kd;AACF;;AqCvgLA;EASM,yBtC7C4B;EsC8C5B,W3BcU;AVo/KhB;;AqC5gLA;;EAcU,W3BUM;AVy/KhB;;AqCjhLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVigLhB;;AqCzhLA;EAwBY,kB3BAI;AVqgLhB;;AqC7hLA;EA0BQ,W3BFQ;AVygLhB;;ACjgLE;EoChCF;;;;IAgCY,W3BRI;EVihLd;EqCziLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV8hLd;EqCtjLF;;IA0Cc,kB3BlBE;EVkiLd;EqC1jLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVwiLd;EqChkLF;IAmDc,yBtCvFoB;IsCwFpB,W3B5BE;EV4iLd;AACF;;AqCrkLA;EASM,yBtC9C4B;EsC+C5B,W3BcU;AVkjLhB;;AqC1kLA;;EAcU,W3BUM;AVujLhB;;AqC/kLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AV+jLhB;;AqCvlLA;EAwBY,kB3BAI;AVmkLhB;;AqC3lLA;EA0BQ,W3BFQ;AVukLhB;;AC/jLE;EoChCF;;;;IAgCY,W3BRI;EV+kLd;EqCvmLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV4lLd;EqCpnLF;;IA0Cc,kB3BlBE;EVgmLd;EqCxnLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVsmLd;EqC9nLF;IAmDc,yBtCxFoB;IsCyFpB,W3B5BE;EV0mLd;AACF;;AqCnoLA;EASM,yBtChD4B;EsCiD5B,W3BcU;AVgnLhB;;AqCxoLA;;EAcU,W3BUM;AVqnLhB;;AqC7oLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AV6nLhB;;AqCrpLA;EAwBY,kB3BAI;AVioLhB;;AqCzpLA;EA0BQ,W3BFQ;AVqoLhB;;AC7nLE;EoChCF;;;;IAgCY,W3BRI;EV6oLd;EqCrqLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV0pLd;EqClrLF;;IA0Cc,kB3BlBE;EV8pLd;EqCtrLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVoqLd;EqC5rLF;IAmDc,yBtC1FoB;IsC2FpB,W3B5BE;EVwqLd;AACF;;AqCjsLA;EASM,yBtCjD4B;EsCkD5B,yB3BYe;AVgrLrB;;AqCtsLA;;EAcU,yB3BQW;AVqrLrB;;AqC3sLA;;;;EAoBY,yB3B8BqB;E2B7BrB,yB3BCS;AV6rLrB;;AqCntLA;EAwBY,gC3BFS;AVisLrB;;AqCvtLA;EA0BQ,yB3BJa;AVqsLrB;;AC3rLE;EoChCF;;;;IAgCY,yB3BVS;EV6sLnB;EqCnuLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,yB3BjBO;EV0tLnB;EqChvLF;;IA0Cc,gC3BpBO;EV8tLnB;EqCpvLF;;;IA8CU,yB3BIuB;I2BHvB,yB3BzBW;EVouLnB;EqC1vLF;IAmDc,yBtC3FoB;IsC4FpB,yB3B9BO;EVwuLnB;AACF;;AqC/vLA;EASM,yBtC3C2B;EsC4C3B,W3BcU;AV4uLhB;;AqCpwLA;;EAcU,W3BUM;AVivLhB;;AqCzwLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVyvLhB;;AqCjxLA;EAwBY,kB3BAI;AV6vLhB;;AqCrxLA;EA0BQ,W3BFQ;AViwLhB;;ACzvLE;EoChCF;;;;IAgCY,W3BRI;EVywLd;EqCjyLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVsxLd;EqC9yLF;;IA0Cc,kB3BlBE;EV0xLd;EqClzLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVgyLd;EqCxzLF;IAmDc,yBtCrFmB;IsCsFnB,W3B5BE;EVoyLd;AACF;;AqC7zLA;EAsDI,oBAAoB;EACpB,aAAa;EACb,mBA7GmB;EA8GnB,WAAW;ArC2wLf;;AqCp0LA;EA2DI,gCtCxG0B;ACq3L9B;;AqCx0LA;EALE,OAAO;EACP,eAAe;EACf,QAAQ;EACR,WA/CiB;ArCg4LnB;;AqC/0LA;EAgEI,SAAS;ArCmxLb;;AqCn1LA;EAkEM,iCtC/GwB;ACo4L9B;;AqCv1LA;EAoEI,MAAM;ArCuxLV;;AqCrxLA;;EAGI,oBA9HmB;ArCq5LvB;;AqC1xLA;;EAKI,uBAhImB;ArC05LvB;;AqCxxLA;;EAEE,oBAAoB;EACpB,aAAa;EACb,cAAc;EACd,mBAvIqB;ArCk6LvB;;AqCzxLA;EAIM,6BAA6B;ArCyxLnC;;AqCvxLA;EpCjFE,iCAAiC;EoCmFjC,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;ArC0xLpB;;AqCxxLA;EAEE,ctCrJ4B;EEoB5B,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,eAAe;EACf,cAAc;EACd,eoC7BqB;EpC8BrB,kBAAkB;EAClB,coC/BqB;EpC+KnB,iBoCtBkC;ArCmyLtC;;AC55LE;EACE,8BAA8B;EAC9B,cAAc;EACd,WAAW;EACX,qBAAqB;EACrB,kBAAkB;EAClB,wBAAwB;EACxB,yBF6BQ;EE5BR,yDAAyD;EACzD,oCFsBa;EErBb,WAAW;AD+5Lf;;AC95LI;EACE,oBAAoB;ADi6L1B;;ACh6LI;EACE,oBAAoB;ADm6L1B;;ACl6LI;EACE,oBAAoB;ADq6L1B;;ACp6LE;EACE,qCAAiC;ADu6LrC;;ACn6LM;EACE,wCAAwC;ADs6LhD;;ACr6LM;EACE,UAAU;ADw6LlB;;ACv6LM;EACE,0CAA0C;AD06LlD;;AqC10LA;EACE,aAAa;ArC60Lf;;AqC30LA;;EAEE,ctC9J4B;EsC+J5B,cAAc;EACd,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;ArC80LpB;;AqCp1LA;;EASM,qBAAqB;EACrB,sBAAsB;ArCg1L5B;;AqC90LA;;EAEE,eAAe;ArCi1LjB;;AqCn1LA;;;;;EAOI,yBtCxK0B;EsCyK1B,ctCjK8B;ACq/LlC;;AqCl1LA;EACE,YAAY;EACZ,cAAc;ArCq1LhB;;AqCv1LA;EAII,mBA7KgC;ArCogMpC;;AqC31LA;EAMI,UAAU;ArCy1Ld;;AqC/1LA;EAQI,YAAY;EACZ,cAAc;ArC21LlB;;AqCp2LA;EAWI,oCAAoC;EACpC,mBAhMmB;EAiMnB,kCAAkC;ArC61LtC;;AqC12LA;EAgBM,6BArLyC;EAsLzC,4BtCpL4B;ACkhMlC;;AqC/2LA;EAmBM,6BArL0C;EAsL1C,4BtCvL4B;EsCwL5B,0BArLuC;EAsLvC,wBArLqC;EAsLrC,ctC1L4B;EsC2L5B,kCAAwE;ArCg2L9E;;AqC91LA;EACE,YAAY;EACZ,cAAc;ArCi2LhB;;AqC/1LA;EpCnCI,oBoCoCoC;ArCk2LxC;;AqCn2LA;EAII,qBtCrM8B;EsCsM9B,oBAAoB;EpChCpB,coCiC6B;ArCm2LjC;;AqCj2LA;EACE,mBAAmB;EACnB,sBAAsB;EACtB,mBAAmB;ArCo2LrB;;AqCv2LA;EAKI,oBAAoB;EACpB,qBAAqB;ArCs2LzB;;AqCp2LA;EACE,4BtC3N4B;EsC4N5B,YAAY;EACZ,aAAa;EACb,WA/LyB;EAgMzB,gBAAgB;ArCu2LlB;;ACr/LE;EoCpCF;IAsLI,cAAc;ErCw2LhB;EqCv2LA;;IAGI,mBAAmB;IACnB,aAAa;ErCw2LjB;EqCv2LA;IAEI,aAAa;ErCw2LjB;EqCh8LF;IA0FI,uBtC3O2B;IsC4O3B,4CtCzPyB;IsC0PzB,iBAAiB;ErCy2LnB;EqC52LA;IAKI,cAAc;ErC02LlB;EqCx2LA;IA3MA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErCqmMjB;EqC92LA;IAKI,SAAS;ErC42Lb;EqCj3LA;IAOM,4CtCrQqB;ECknM3B;EqCp3LA;IASI,MAAM;ErC82LV;EqCv3LA;IpC7LA,iCAAiC;IoC2M3B,iCAA2C;IAC3C,cAAc;ErC62LpB;EqC52LA;;IAGI,oBA9QiB;ErC2nMrB;EqCh3LA;;IAKI,uBAhRiB;ErC+nMrB;AACF;;AC3iME;EoC8LA;;;;IAIE,oBAAoB;IACpB,aAAa;ErCi3Lf;EqCplMF;IAqOI,mBA1RmB;ErC4oMrB;EqCn3LA;IAGI,kBA1R0B;ErC6oM9B;EqCt3LA;;IAMM,mBAAmB;ErCo3LzB;EqC13LA;;IASM,kBtCjOI;ECslMV;EqC93LA;;;;IAgBQ,wCAAwC;ErCo3LhD;EqCp4LA;IAuBU,wCAAwC;ErCg3LlD;EqCv4LA;IA4BU,4BtC7SkB;IsC8SlB,ctCzTiB;ECuqM3B;EqC34LA;IA+BU,4BtChTkB;IsCiTlB,ctCxSsB;ECupMhC;EqCnhMF;IAsKI,aAAa;ErCg3Lf;EqC7gMF;;IAgKI,mBAAmB;IACnB,aAAa;ErCi3Lf;EqC5/LF;IA8IM,oBAAoB;ErCi3LxB;EqCn3LA;IAKM,oDAAoD;ErCi3L1D;EqCt3LA;IAOM,gCtClUsB;IsCmUtB,0BAAkE;IAClE,gBAAgB;IAChB,YAAY;IACZ,4CtC9UqB;IsC+UrB,SAAS;ErCk3Lf;EqC93LA;IAkBM,cAAc;ErC+2LpB;EqC92LM;IAEE,UAAU;IACV,oBAAoB;IACpB,wBAAwB;ErC+2LhC;EqC3iMF;IA8LI,YAAY;IACZ,cAAc;ErCg3LhB;EqC/2LA;IACE,2BAA2B;IpC7K3B,kBoC8KoC;ErCi3LtC;EqCh3LA;IACE,yBAAyB;IpChLzB,iBoCiLoC;ErCk3LtC;EqCx/LF;IAwII,uBtCxV2B;IsCyV3B,8BtCjSc;IsCkSd,+BtClSc;IsCmSd,6BtChW0B;IsCiW1B,2CtCzWyB;IsC0WzB,aAAa;IACb,mBAAmB;IpCjLnB,OoCkLuB;IACvB,eAAe;IACf,kBAAkB;IAClB,SAAS;IACT,WAjVkB;ErCosMpB;EqCtgMF;IAqJM,sBAAsB;IACtB,mBAAmB;ErCo3LvB;EqCn4LA;IpClLE,mBoCmMuC;ErCq3LzC;EqCt4LA;IAoBM,4BtC7WsB;IsC8WtB,ctCzXqB;EC8uM3B;EqC14LA;IAuBM,4BtChXsB;IsCiXtB,ctCxW0B;EC8tMhC;EqCr3LE;IAEE,kBtC1TY;IsC2TZ,gBAAgB;IAChB,4EtCjYuB;IsCkYvB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,wBAA8C;IAC9C,2BAA2B;IAC3B,yBtChUM;IsCiUN,uCAAuC;ErCs3L3C;EqC15LA;IAsCI,UAAU;IACV,QAAQ;ErCu3LZ;EqC7hMF;IAwKI,cAAc;ErCw3LhB;EqCv3LA;;IpC5NE,qBoC+NyC;ErCw3L3C;EqC33LA;;IpC5NE,sBoCiOyC;ErC03L3C;EqCx3LA;IAlWA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErC4wMjB;EqC93LA;IAKI,SAAS;ErC43Lb;EqCj4LA;IAOM,4CtC5ZqB;ECyxM3B;EqCp4LA;IASI,MAAM;ErC83LV;EqC73LA;;IAGI,oBA/ZiB;ErC6xMrB;EqCj4LA;;IAKI,uBAjaiB;ErCiyMrB;EqCr4LA;;IAOI,oBAA4D;ErCk4LhE;EqCz4LA;;IASI,uBAA+D;ErCo4LnE;EqCl4LA;;IAGI,ctC7auB;ECgzM3B;EqCt4LA;;IAKI,6BAla2C;ErCuyM/C;EqCp4LA;IAKM,yBtCzasB;EC2yM5B;AACF;;AqC/3LA;EAEI,iCAA2C;ArCi4L/C;;AsCzxMA;EAEE,evCFW;EuCGX,gBAnC0B;AtC8zM5B;;AsC9xMA;EAMI,kBvCLY;ACiyMhB;;AsClyMA;EAQI,kBvCTY;ACuyMhB;;AsCtyMA;EAUI,iBvCZW;AC4yMf;;AsC1yMA;;EAcM,iBAAiB;EACjB,kBAAkB;EAClB,qBvCmBiB;AC8wMvB;;AsCjzMA;EAkBM,qBvCiBiB;ACkxMvB;;AsCjyMA;;EAEE,mBAAmB;EACnB,aAAa;EACb,uBAAuB;EACvB,kBAAkB;AtCoyMpB;;AsClyMA;;;;EAME,cA9D6B;EA+D7B,uBAAuB;EACvB,eA/D8B;EAgE9B,mBA/DkC;EAgElC,oBA/DmC;EAgEnC,kBAAkB;AtCmyMpB;;AsCjyMA;;;EAGE,qBvCtE4B;EuCuE5B,cvC3E4B;EuC4E5B,gBxC3EoB;AE+2MtB;;AsCzyMA;;;EAOI,qBvC3E0B;EuC4E1B,cvC/E0B;ACu3M9B;;AsChzMA;;;EAUI,qBvCjE8B;AC62MlC;;AsCtzMA;;;EAYI,iDvCvFyB;ACu4M7B;;AsC5zMA;;;;;EAeI,yBvClF0B;EuCmF1B,qBvCnF0B;EuCoF1B,gBAAgB;EAChB,cvCvF0B;EuCwF1B,YAAY;AtCqzMhB;;AsCnzMA;;EAEE,oBAvFkC;EAwFlC,qBAvFmC;EAwFnC,mBAAmB;AtCszMrB;;AsCpzMA;EAEI,yBvCpF8B;EuCqF9B,qBvCrF8B;EuCsF9B,W5B1BY;AVg1MhB;;AsCpzMA;EACE,cvCtG4B;EuCuG5B,oBAAoB;AtCuzMtB;;AsCrzMA;EACE,eAAe;AtCwzMjB;;AsCzzMA;EAGI,gBAAgB;AtC0zMpB;;ACz0ME;EqCjEF;IAoFI,eAAe;EtC2zMjB;EsCl1MF;;IA0BI,YAAY;IACZ,cAAc;EtC4zMhB;EsCv0MF;IAcM,YAAY;IACZ,cAAc;EtC4zMlB;AACF;;ACp1ME;EqCQF;IAmBI,YAAY;IACZ,cAAc;IACd,2BAA2B;IAC3B,QAAQ;EtC8zMV;EsCt4MF;;;;IA6EI,gBAAgB;IAChB,aAAa;EtC+zMf;EsC9zMA;IACE,QAAQ;EtCg0MV;EsC/zMA;IACE,QAAQ;EtCi0MV;EsC96MF;IA+GI,8BAA8B;IAC9B,gBAAgB;IAChB,aAAa;EtCk0Mf;EsCr0MA;IAMM,QAAQ;EtCk0Md;EsCx0MA;IAQM,uBAAuB;IACvB,QAAQ;EtCm0Md;EsC50MA;IAWM,QAAQ;EtCo0Md;EsC/0MA;IAcM,QAAQ;EtCo0Md;EsCl1MA;IAgBM,QAAQ;EtCq0Md;EsCr1MA;IAkBM,yBAAyB;IACzB,QAAQ;EtCs0Md;AACF;;AuC78MA;EACE,kBxCsCgB;EwCrChB,0FxChC2B;EwCiC3B,exCEW;AC88Mb;;AuCn9MA;EAKI,qBxCWkB;ACu8MtB;;AuCv9MA;EAYQ,uBxC7BuB;EwC8BvB,cxC3CqB;AC0/M7B;;AuC59MA;EAeQ,0BxChCuB;ACi/M/B;;AuCh+MA;EAiBQ,YxClCuB;ACq/M/B;;AuCp+MA;EAYQ,yBxC1CqB;EwC2CrB,YxC9BuB;AC0/M/B;;AuCz+MA;EAeQ,4BxC7CqB;AC2gN7B;;AuC7+MA;EAiBQ,cxC/CqB;AC+gN7B;;AuCj/MA;EAYQ,4BxC/BsB;EwCgCtB,yB7BmCa;AVs8MrB;;AuCt/MA;EAeQ,+BxClCsB;AC6gN9B;;AuC1/MA;EAiBQ,iBxCpCsB;ACihN9B;;AuC9/MA;EAYQ,yBxCtCsB;EwCuCtB,W7BqCQ;AVi9MhB;;AuCngNA;EAeQ,4BxCzCsB;ACiiN9B;;AuCvgNA;EAiBQ,cxC3CsB;ACqiN9B;;AuC3gNA;EAYQ,yBxCxB0B;EwCyB1B,W7BqCQ;AV89MhB;;AuChhNA;EAeQ,4BxC3B0B;ACgiNlC;;AuCphNA;EAiBQ,cxC7B0B;ACoiNlC;;AuCxhNA;EAYQ,yBxCtB0B;EwCuB1B,W7BqCQ;AV2+MhB;;AuC7hNA;EAeQ,4BxCzB0B;AC2iNlC;;AuCjiNA;EAiBQ,cxC3B0B;AC+iNlC;;AuCriNA;EAYQ,yBxCvB0B;EwCwB1B,W7BqCQ;AVw/MhB;;AuC1iNA;EAeQ,4BxC1B0B;ACyjNlC;;AuC9iNA;EAiBQ,cxC5B0B;AC6jNlC;;AuCljNA;EAYQ,yBxCzB0B;EwC0B1B,W7BqCQ;AVqgNhB;;AuCvjNA;EAeQ,4BxC5B0B;ACwkNlC;;AuC3jNA;EAiBQ,cxC9B0B;AC4kNlC;;AuC/jNA;EAYQ,yBxC1B0B;EwC2B1B,yB7BmCa;AVohNrB;;AuCpkNA;EAeQ,4BxC7B0B;ACslNlC;;AuCxkNA;EAiBQ,cxC/B0B;AC0lNlC;;AuC5kNA;EAYQ,yBxCpByB;EwCqBzB,W7BqCQ;AV+hNhB;;AuCjlNA;EAeQ,4BxCvByB;AC6lNjC;;AuCrlNA;EAiBQ,cxCzByB;ACimNjC;;AuCtkNA;;EAGI,gCxC3C2B;ACmnN/B;;AuCtkNA;EACE,yBxC9C6B;EwC+C7B,0BAA8C;EAC9C,cxCrD4B;EwCsD5B,iBAhDyB;EAiDzB,gBxCjBe;EwCkBf,iBArD8B;EAsD9B,mBArDgC;AvC8nNlC;;AuCvkNA;EACE,qBAAqB;EACrB,aAAa;EACb,kBArD4B;EAsD5B,uBAAuB;AvC0kNzB;;AuC9kNA;EAMI,gCxC7D0B;EwC8D1B,mBAAmB;EACnB,cAAc;AvC4kNlB;;AuCplNA;EAWM,4BxCrEwB;EwCsExB,cxCvEwB;ACopN9B;;AuC3kNA;EAEI,cxC1E0B;ACupN9B;;AuC/kNA;EAIM,cxC7D4B;AC4oNlC;;AuC7kNA;EACE,mBAAmB;EACnB,cxCjF4B;EwCkF5B,aAAa;EACb,2BAA2B;EAC3B,qBAAqB;AvCglNvB;;AuCrlNA;EtC+FI,oBsCxFsC;AvCklN1C;;AuCzlNA;EASI,YAAY;EACZ,cAAc;EACd,WAAW;AvColNf;;AuC/lNA;EAaI,eAAe;AvCslNnB;;AuCnmNA;EAeI,0BxC9E8B;EwC+E9B,cxC/F0B;ACurN9B;;AuCxmNA;EAkBM,cxCjF4B;AC2qNlC;;AuC5mNA;EAoBI,8BxClCc;EwCmCd,+BxCnCc;AC+nNlB;;AuC1lNA;;EAEE,eAAe;AvC6lNjB;;AuC/lNA;;EAII,4BxCnG0B;ACmsN9B;;AuC9lNA;EtChGE,qBAAqB;EACrB,esCgGgB;EtC/FhB,WsC+FqB;EtC9FrB,gBsC8FqB;EtC7FrB,kBAAkB;EAClB,mBAAmB;EACnB,UsC2FqB;EACrB,cxC5G4B;EE4K1B,oBsC/DoC;AvCumNxC;;AuC1mNA;EAKI,kBAAkB;EAClB,oBAAoB;AvCymNxB;;AwCnsNA;EvCqCE,iCAAiC;EuCjCjC,oBAAoB;EACpB,aAAa;EACb,ezCCW;EyCAX,8BAA8B;EAC9B,gBAAgB;EAChB,gBAAgB;EAChB,mBAAmB;AxCosNrB;;AwC9sNA;EAYI,mBAAmB;EACnB,4BzCjC0B;EyCkC1B,0BAzC4B;EA0C5B,wBAzC0B;EA0C1B,czCvC0B;EyCwC1B,aAAa;EACb,uBAAuB;EACvB,mBAA6C;EAC7C,kBAxCyB;EAyCzB,mBAAmB;AxCssNvB;;AwC3tNA;EAuBM,4BzC/CwB;EyCgDxB,czChDwB;ACwvN9B;;AwChuNA;EA0BI,cAAc;AxC0sNlB;;AwCpuNA;EA6BQ,4BzCrC0B;EyCsC1B,czCtC0B;ACivNlC;;AwCzuNA;EAgCI,mBAAmB;EACnB,4BzCrD0B;EyCsD1B,0BA7D4B;EA8D5B,wBA7D0B;EA8D1B,aAAa;EACb,YAAY;EACZ,cAAc;EACd,2BAA2B;AxC6sN/B;;AwCpvNA;EAyCM,qBAAqB;AxC+sN3B;;AwCxvNA;EA2CM,UAAU;EACV,uBAAuB;EACvB,oBAAoB;EACpB,qBAAqB;AxCitN3B;;AwC/vNA;EAgDM,yBAAyB;EACzB,oBAAoB;AxCmtN1B;;AwCpwNA;EvCsJI,mBuClGuC;AxCotN3C;;AwCxwNA;EvCsJI,kBuChGuC;AxCstN3C;;AwC5wNA;EA0DM,uBAAuB;AxCstN7B;;AwChxNA;EA6DM,yBAAyB;AxCutN/B;;AwCpxNA;EAiEM,6BAA6B;EAE3B,0BAAkE;AxCstN1E;;AwCzxNA;EAuEQ,4BzCxFsB;EyCyFtB,4BzC5FsB;ACkzN9B;;AwC9xNA;EA4EU,uBzC3FqB;EyC4FrB,qBzCjGoB;EyCkGpB,2CAA2E;AxCstNrF;;AwCpyNA;EAiFM,YAAY;EACZ,cAAc;AxCutNpB;;AwCzyNA;EAqFM,qBzCzGwB;EyC0GxB,mBA/F+B;EAgG/B,iBA/F6B;EAgG7B,gBAAgB;EAChB,kBAAkB;AxCwtNxB;;AwCjzNA;EA2FQ,4BzC5GsB;EyC6GtB,qBzCjHsB;EyCkHtB,UAAU;AxC0tNlB;;AwCvzNA;EvCsJI,iBuCtDuE;AxC2tN3E;;AwC3zNA;EAmGU,2BzC3DE;EyC4DF,8BzC5DE;ACwxNZ;;AwCh0NA;EA0GU,4BzClEE;EyCmEF,+BzCnEE;AC6xNZ;;AwCr0NA;EAiHU,yBzCzHwB;EyC0HxB,qBzC1HwB;EyC2HxB,W9B/DM;E8BgEN,UAAU;AxCwtNpB;;AwC50NA;EAsHM,mBAAmB;AxC0tNzB;;AwCh1NA;EA2HY,iCzCjFW;EyCkFX,8BzClFW;EyCmFX,oBAAoB;AxCytNhC;;AwCt1NA;EAoIY,kCzC1FW;EyC2FX,+BzC3FW;EyC4FX,qBAAqB;AxCstNjC;;AwC51NA;EA6II,kBzCrIY;ACw1NhB;;AwCh2NA;EA+II,kBzCzIY;AC81NhB;;AwCp2NA;EAiJI,iBzC5IW;ACm2Nf;;AyCt4NA,eAAA;ACIA;EACE,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,gBAPkB;A1C64NpB;;A0Cr4NE;EACE,UAAU;EACV,YAAY;A1Cw4NhB;;A0Cv4NE;EACE,UAAU;EACV,WAAW;A1C04Nf;;A0Cz4NE;EACE,UAAU;EACV,UAAU;A1C44Nd;;A0C34NE;EACE,UAAU;EACV,eAAe;A1C84NnB;;A0C74NE;EACE,UAAU;EACV,UAAU;A1Cg5Nd;;A0C/4NE;EACE,UAAU;EACV,eAAe;A1Ck5NnB;;A0Cj5NE;EACE,UAAU;EACV,UAAU;A1Co5Nd;;A0Cn5NE;EACE,UAAU;EACV,UAAU;A1Cs5Nd;;A0Cr5NE;EACE,UAAU;EACV,UAAU;A1Cw5Nd;;A0Cv5NE;EACE,UAAU;EACV,UAAU;A1C05Nd;;A0Cz5NE;EACE,UAAU;EACV,UAAU;A1C45Nd;;A0C35NE;EzCyIE,gByCxImC;A1C85NvC;;A0C75NE;EzCuIE,qByCtIwC;A1Cg6N5C;;A0C/5NE;EzCqIE,gByCpImC;A1Ck6NvC;;A0Cj6NE;EzCmIE,qByClIwC;A1Co6N5C;;A0Cn6NE;EzCiIE,gByChImC;A1Cs6NvC;;A0Cr6NE;EzC+HE,gByC9HmC;A1Cw6NvC;;A0Cv6NE;EzC6HE,gByC5HmC;A1C06NvC;;A0Cz6NE;EzC2HE,gByC1HmC;A1C46NvC;;A0C36NE;EzCyHE,gByCxHmC;A1C86NvC;;A0C56NI;EACE,UAAU;EACV,SAAiC;A1C+6NvC;;A0C96NI;EzCmHA,eyClH4D;A1Ci7NhE;;A0Cr7NI;EACE,UAAU;EACV,eAAiC;A1Cw7NvC;;A0Cv7NI;EzCmHA,qByClH4D;A1C07NhE;;A0C97NI;EACE,UAAU;EACV,gBAAiC;A1Ci8NvC;;A0Ch8NI;EzCmHA,sByClH4D;A1Cm8NhE;;A0Cv8NI;EACE,UAAU;EACV,UAAiC;A1C08NvC;;A0Cz8NI;EzCmHA,gByClH4D;A1C48NhE;;A0Ch9NI;EACE,UAAU;EACV,gBAAiC;A1Cm9NvC;;A0Cl9NI;EzCmHA,sByClH4D;A1Cq9NhE;;A0Cz9NI;EACE,UAAU;EACV,gBAAiC;A1C49NvC;;A0C39NI;EzCmHA,sByClH4D;A1C89NhE;;A0Cl+NI;EACE,UAAU;EACV,UAAiC;A1Cq+NvC;;A0Cp+NI;EzCmHA,gByClH4D;A1Cu+NhE;;A0C3+NI;EACE,UAAU;EACV,gBAAiC;A1C8+NvC;;A0C7+NI;EzCmHA,sByClH4D;A1Cg/NhE;;A0Cp/NI;EACE,UAAU;EACV,gBAAiC;A1Cu/NvC;;A0Ct/NI;EzCmHA,sByClH4D;A1Cy/NhE;;A0C7/NI;EACE,UAAU;EACV,UAAiC;A1CggOvC;;A0C//NI;EzCmHA,gByClH4D;A1CkgOhE;;A0CtgOI;EACE,UAAU;EACV,gBAAiC;A1CygOvC;;A0CxgOI;EzCmHA,sByClH4D;A1C2gOhE;;A0C/gOI;EACE,UAAU;EACV,gBAAiC;A1CkhOvC;;A0CjhOI;EzCmHA,sByClH4D;A1CohOhE;;A0CxhOI;EACE,UAAU;EACV,WAAiC;A1C2hOvC;;A0C1hOI;EzCmHA,iByClH4D;A1C6hOhE;;ACz/NE;EyClGF;IAiEM,UAAU;IACV,YAAY;E1C+hOhB;E0CjmOF;IAoEM,UAAU;IACV,WAAW;E1CgiOf;E0CrmOF;IAuEM,UAAU;IACV,UAAU;E1CiiOd;E0CzmOF;IA0EM,UAAU;IACV,eAAe;E1CkiOnB;E0C7mOF;IA6EM,UAAU;IACV,UAAU;E1CmiOd;E0CjnOF;IAgFM,UAAU;IACV,eAAe;E1CoiOnB;E0CrnOF;IAmFM,UAAU;IACV,UAAU;E1CqiOd;E0CznOF;IAsFM,UAAU;IACV,UAAU;E1CsiOd;E0C7nOF;IAyFM,UAAU;IACV,UAAU;E1CuiOd;E0CjoOF;IA4FM,UAAU;IACV,UAAU;E1CwiOd;E0CroOF;IA+FM,UAAU;IACV,UAAU;E1CyiOd;E0CzoOF;IzCgLI,gByC9EqC;E1C0iOvC;E0C5oOF;IzCgLI,qByC5E0C;E1C2iO5C;E0C/oOF;IzCgLI,gByC1EqC;E1C4iOvC;E0ClpOF;IzCgLI,qByCxE0C;E1C6iO5C;E0CrpOF;IzCgLI,gByCtEqC;E1C8iOvC;E0CxpOF;IzCgLI,gByCpEqC;E1C+iOvC;E0C3pOF;IzCgLI,gByClEqC;E1CgjOvC;E0C9pOF;IzCgLI,gByChEqC;E1CijOvC;E0CjqOF;IzCgLI,gByC9DqC;E1CkjOvC;E0CpqOF;IAqHQ,UAAU;IACV,SAAiC;E1CkjOvC;E0CxqOF;IzCgLI,eyCxD8D;E1CmjOhE;E0C3qOF;IAqHQ,UAAU;IACV,eAAiC;E1CyjOvC;E0C/qOF;IzCgLI,qByCxD8D;E1C0jOhE;E0ClrOF;IAqHQ,UAAU;IACV,gBAAiC;E1CgkOvC;E0CtrOF;IzCgLI,sByCxD8D;E1CikOhE;E0CzrOF;IAqHQ,UAAU;IACV,UAAiC;E1CukOvC;E0C7rOF;IzCgLI,gByCxD8D;E1CwkOhE;E0ChsOF;IAqHQ,UAAU;IACV,gBAAiC;E1C8kOvC;E0CpsOF;IzCgLI,sByCxD8D;E1C+kOhE;E0CvsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CqlOvC;E0C3sOF;IzCgLI,sByCxD8D;E1CslOhE;E0C9sOF;IAqHQ,UAAU;IACV,UAAiC;E1C4lOvC;E0CltOF;IzCgLI,gByCxD8D;E1C6lOhE;E0CrtOF;IAqHQ,UAAU;IACV,gBAAiC;E1CmmOvC;E0CztOF;IzCgLI,sByCxD8D;E1ComOhE;E0C5tOF;IAqHQ,UAAU;IACV,gBAAiC;E1C0mOvC;E0ChuOF;IzCgLI,sByCxD8D;E1C2mOhE;E0CnuOF;IAqHQ,UAAU;IACV,UAAiC;E1CinOvC;E0CvuOF;IzCgLI,gByCxD8D;E1CknOhE;E0C1uOF;IAqHQ,UAAU;IACV,gBAAiC;E1CwnOvC;E0C9uOF;IzCgLI,sByCxD8D;E1CynOhE;E0CjvOF;IAqHQ,UAAU;IACV,gBAAiC;E1C+nOvC;E0CrvOF;IzCgLI,sByCxD8D;E1CgoOhE;E0CxvOF;IAqHQ,UAAU;IACV,WAAiC;E1CsoOvC;E0C5vOF;IzCgLI,iByCxD8D;E1CuoOhE;AACF;;AC1pOE;EyCtGF;IA4HM,UAAU;IACV,YAAY;E1CyoOhB;E0CtwOF;IAgIM,UAAU;IACV,WAAW;E1CyoOf;E0C1wOF;IAoIM,UAAU;IACV,UAAU;E1CyoOd;E0C9wOF;IAwIM,UAAU;IACV,eAAe;E1CyoOnB;E0ClxOF;IA4IM,UAAU;IACV,UAAU;E1CyoOd;E0CtxOF;IAgJM,UAAU;IACV,eAAe;E1CyoOnB;E0C1xOF;IAoJM,UAAU;IACV,UAAU;E1CyoOd;E0C9xOF;IAwJM,UAAU;IACV,UAAU;E1CyoOd;E0ClyOF;IA4JM,UAAU;IACV,UAAU;E1CyoOd;E0CtyOF;IAgKM,UAAU;IACV,UAAU;E1CyoOd;E0C1yOF;IAoKM,UAAU;IACV,UAAU;E1CyoOd;E0C9yOF;IzCgLI,gByCRqC;E1CyoOvC;E0CjzOF;IzCgLI,qByCL0C;E1CyoO5C;E0CpzOF;IzCgLI,gByCFqC;E1CyoOvC;E0CvzOF;IzCgLI,qByCC0C;E1CyoO5C;E0C1zOF;IzCgLI,gByCIqC;E1CyoOvC;E0C7zOF;IzCgLI,gByCOqC;E1CyoOvC;E0Ch0OF;IzCgLI,gByCUqC;E1CyoOvC;E0Cn0OF;IzCgLI,gByCaqC;E1CyoOvC;E0Ct0OF;IzCgLI,gByCgBqC;E1CyoOvC;E0Cz0OF;IAoMQ,UAAU;IACV,SAAiC;E1CwoOvC;E0C70OF;IzCgLI,eyCwB8D;E1CwoOhE;E0Ch1OF;IAoMQ,UAAU;IACV,eAAiC;E1C+oOvC;E0Cp1OF;IzCgLI,qByCwB8D;E1C+oOhE;E0Cv1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CspOvC;E0C31OF;IzCgLI,sByCwB8D;E1CspOhE;E0C91OF;IAoMQ,UAAU;IACV,UAAiC;E1C6pOvC;E0Cl2OF;IzCgLI,gByCwB8D;E1C6pOhE;E0Cr2OF;IAoMQ,UAAU;IACV,gBAAiC;E1CoqOvC;E0Cz2OF;IzCgLI,sByCwB8D;E1CoqOhE;E0C52OF;IAoMQ,UAAU;IACV,gBAAiC;E1C2qOvC;E0Ch3OF;IzCgLI,sByCwB8D;E1C2qOhE;E0Cn3OF;IAoMQ,UAAU;IACV,UAAiC;E1CkrOvC;E0Cv3OF;IzCgLI,gByCwB8D;E1CkrOhE;E0C13OF;IAoMQ,UAAU;IACV,gBAAiC;E1CyrOvC;E0C93OF;IzCgLI,sByCwB8D;E1CyrOhE;E0Cj4OF;IAoMQ,UAAU;IACV,gBAAiC;E1CgsOvC;E0Cr4OF;IzCgLI,sByCwB8D;E1CgsOhE;E0Cx4OF;IAoMQ,UAAU;IACV,UAAiC;E1CusOvC;E0C54OF;IzCgLI,gByCwB8D;E1CusOhE;E0C/4OF;IAoMQ,UAAU;IACV,gBAAiC;E1C8sOvC;E0Cn5OF;IzCgLI,sByCwB8D;E1C8sOhE;E0Ct5OF;IAoMQ,UAAU;IACV,gBAAiC;E1CqtOvC;E0C15OF;IzCgLI,sByCwB8D;E1CqtOhE;E0C75OF;IAoMQ,UAAU;IACV,WAAiC;E1C4tOvC;E0Cj6OF;IzCgLI,iByCwB8D;E1C4tOhE;AACF;;ACvzOE;EyC9GF;IA2MM,UAAU;IACV,YAAY;E1C+tOhB;E0C36OF;IA8MM,UAAU;IACV,WAAW;E1CguOf;E0C/6OF;IAiNM,UAAU;IACV,UAAU;E1CiuOd;E0Cn7OF;IAoNM,UAAU;IACV,eAAe;E1CkuOnB;E0Cv7OF;IAuNM,UAAU;IACV,UAAU;E1CmuOd;E0C37OF;IA0NM,UAAU;IACV,eAAe;E1CouOnB;E0C/7OF;IA6NM,UAAU;IACV,UAAU;E1CquOd;E0Cn8OF;IAgOM,UAAU;IACV,UAAU;E1CsuOd;E0Cv8OF;IAmOM,UAAU;IACV,UAAU;E1CuuOd;E0C38OF;IAsOM,UAAU;IACV,UAAU;E1CwuOd;E0C/8OF;IAyOM,UAAU;IACV,UAAU;E1CyuOd;E0Cn9OF;IzCgLI,gByC4DqC;E1C0uOvC;E0Ct9OF;IzCgLI,qByC8D0C;E1C2uO5C;E0Cz9OF;IzCgLI,gByCgEqC;E1C4uOvC;E0C59OF;IzCgLI,qByCkE0C;E1C6uO5C;E0C/9OF;IzCgLI,gByCoEqC;E1C8uOvC;E0Cl+OF;IzCgLI,gByCsEqC;E1C+uOvC;E0Cr+OF;IzCgLI,gByCwEqC;E1CgvOvC;E0Cx+OF;IzCgLI,gByC0EqC;E1CivOvC;E0C3+OF;IzCgLI,gByC4EqC;E1CkvOvC;E0C9+OF;IA+PQ,UAAU;IACV,SAAiC;E1CkvOvC;E0Cl/OF;IzCgLI,eyCkF8D;E1CmvOhE;E0Cr/OF;IA+PQ,UAAU;IACV,eAAiC;E1CyvOvC;E0Cz/OF;IzCgLI,qByCkF8D;E1C0vOhE;E0C5/OF;IA+PQ,UAAU;IACV,gBAAiC;E1CgwOvC;E0ChgPF;IzCgLI,sByCkF8D;E1CiwOhE;E0CngPF;IA+PQ,UAAU;IACV,UAAiC;E1CuwOvC;E0CvgPF;IzCgLI,gByCkF8D;E1CwwOhE;E0C1gPF;IA+PQ,UAAU;IACV,gBAAiC;E1C8wOvC;E0C9gPF;IzCgLI,sByCkF8D;E1C+wOhE;E0CjhPF;IA+PQ,UAAU;IACV,gBAAiC;E1CqxOvC;E0CrhPF;IzCgLI,sByCkF8D;E1CsxOhE;E0CxhPF;IA+PQ,UAAU;IACV,UAAiC;E1C4xOvC;E0C5hPF;IzCgLI,gByCkF8D;E1C6xOhE;E0C/hPF;IA+PQ,UAAU;IACV,gBAAiC;E1CmyOvC;E0CniPF;IzCgLI,sByCkF8D;E1CoyOhE;E0CtiPF;IA+PQ,UAAU;IACV,gBAAiC;E1C0yOvC;E0C1iPF;IzCgLI,sByCkF8D;E1C2yOhE;E0C7iPF;IA+PQ,UAAU;IACV,UAAiC;E1CizOvC;E0CjjPF;IzCgLI,gByCkF8D;E1CkzOhE;E0CpjPF;IA+PQ,UAAU;IACV,gBAAiC;E1CwzOvC;E0CxjPF;IzCgLI,sByCkF8D;E1CyzOhE;E0C3jPF;IA+PQ,UAAU;IACV,gBAAiC;E1C+zOvC;E0C/jPF;IzCgLI,sByCkF8D;E1Cg0OhE;E0ClkPF;IA+PQ,UAAU;IACV,WAAiC;E1Cs0OvC;E0CtkPF;IzCgLI,iByCkF8D;E1Cu0OhE;AACF;;ACx9OE;EyClHF;IAqQM,UAAU;IACV,YAAY;E1C00OhB;E0ChlPF;IAwQM,UAAU;IACV,WAAW;E1C20Of;E0CplPF;IA2QM,UAAU;IACV,UAAU;E1C40Od;E0CxlPF;IA8QM,UAAU;IACV,eAAe;E1C60OnB;E0C5lPF;IAiRM,UAAU;IACV,UAAU;E1C80Od;E0ChmPF;IAoRM,UAAU;IACV,eAAe;E1C+0OnB;E0CpmPF;IAuRM,UAAU;IACV,UAAU;E1Cg1Od;E0CxmPF;IA0RM,UAAU;IACV,UAAU;E1Ci1Od;E0C5mPF;IA6RM,UAAU;IACV,UAAU;E1Ck1Od;E0ChnPF;IAgSM,UAAU;IACV,UAAU;E1Cm1Od;E0CpnPF;IAmSM,UAAU;IACV,UAAU;E1Co1Od;E0CxnPF;IzCgLI,gByCsHqC;E1Cq1OvC;E0C3nPF;IzCgLI,qByCwH0C;E1Cs1O5C;E0C9nPF;IzCgLI,gByC0HqC;E1Cu1OvC;E0CjoPF;IzCgLI,qByC4H0C;E1Cw1O5C;E0CpoPF;IzCgLI,gByC8HqC;E1Cy1OvC;E0CvoPF;IzCgLI,gByCgIqC;E1C01OvC;E0C1oPF;IzCgLI,gByCkIqC;E1C21OvC;E0C7oPF;IzCgLI,gByCoIqC;E1C41OvC;E0ChpPF;IzCgLI,gByCsIqC;E1C61OvC;E0CnpPF;IAyTQ,UAAU;IACV,SAAiC;E1C61OvC;E0CvpPF;IzCgLI,eyC4I8D;E1C81OhE;E0C1pPF;IAyTQ,UAAU;IACV,eAAiC;E1Co2OvC;E0C9pPF;IzCgLI,qByC4I8D;E1Cq2OhE;E0CjqPF;IAyTQ,UAAU;IACV,gBAAiC;E1C22OvC;E0CrqPF;IzCgLI,sByC4I8D;E1C42OhE;E0CxqPF;IAyTQ,UAAU;IACV,UAAiC;E1Ck3OvC;E0C5qPF;IzCgLI,gByC4I8D;E1Cm3OhE;E0C/qPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cy3OvC;E0CnrPF;IzCgLI,sByC4I8D;E1C03OhE;E0CtrPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cg4OvC;E0C1rPF;IzCgLI,sByC4I8D;E1Ci4OhE;E0C7rPF;IAyTQ,UAAU;IACV,UAAiC;E1Cu4OvC;E0CjsPF;IzCgLI,gByC4I8D;E1Cw4OhE;E0CpsPF;IAyTQ,UAAU;IACV,gBAAiC;E1C84OvC;E0CxsPF;IzCgLI,sByC4I8D;E1C+4OhE;E0C3sPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cq5OvC;E0C/sPF;IzCgLI,sByC4I8D;E1Cs5OhE;E0CltPF;IAyTQ,UAAU;IACV,UAAiC;E1C45OvC;E0CttPF;IzCgLI,gByC4I8D;E1C65OhE;E0CztPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cm6OvC;E0C7tPF;IzCgLI,sByC4I8D;E1Co6OhE;E0ChuPF;IAyTQ,UAAU;IACV,gBAAiC;E1C06OvC;E0CpuPF;IzCgLI,sByC4I8D;E1C26OhE;E0CvuPF;IAyTQ,UAAU;IACV,WAAiC;E1Ci7OvC;E0C3uPF;IzCgLI,iByC4I8D;E1Ck7OhE;AACF;;AC9mPI;EyCjIJ;IA+TM,UAAU;IACV,YAAY;E1Cq7OhB;E0CrvPF;IAkUM,UAAU;IACV,WAAW;E1Cs7Of;E0CzvPF;IAqUM,UAAU;IACV,UAAU;E1Cu7Od;E0C7vPF;IAwUM,UAAU;IACV,eAAe;E1Cw7OnB;E0CjwPF;IA2UM,UAAU;IACV,UAAU;E1Cy7Od;E0CrwPF;IA8UM,UAAU;IACV,eAAe;E1C07OnB;E0CzwPF;IAiVM,UAAU;IACV,UAAU;E1C27Od;E0C7wPF;IAoVM,UAAU;IACV,UAAU;E1C47Od;E0CjxPF;IAuVM,UAAU;IACV,UAAU;E1C67Od;E0CrxPF;IA0VM,UAAU;IACV,UAAU;E1C87Od;E0CzxPF;IA6VM,UAAU;IACV,UAAU;E1C+7Od;E0C7xPF;IzCgLI,gByCgLqC;E1Cg8OvC;E0ChyPF;IzCgLI,qByCkL0C;E1Ci8O5C;E0CnyPF;IzCgLI,gByCoLqC;E1Ck8OvC;E0CtyPF;IzCgLI,qByCsL0C;E1Cm8O5C;E0CzyPF;IzCgLI,gByCwLqC;E1Co8OvC;E0C5yPF;IzCgLI,gByC0LqC;E1Cq8OvC;E0C/yPF;IzCgLI,gByC4LqC;E1Cs8OvC;E0ClzPF;IzCgLI,gByC8LqC;E1Cu8OvC;E0CrzPF;IzCgLI,gByCgMqC;E1Cw8OvC;E0CxzPF;IAmXQ,UAAU;IACV,SAAiC;E1Cw8OvC;E0C5zPF;IzCgLI,eyCsM8D;E1Cy8OhE;E0C/zPF;IAmXQ,UAAU;IACV,eAAiC;E1C+8OvC;E0Cn0PF;IzCgLI,qByCsM8D;E1Cg9OhE;E0Ct0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cs9OvC;E0C10PF;IzCgLI,sByCsM8D;E1Cu9OhE;E0C70PF;IAmXQ,UAAU;IACV,UAAiC;E1C69OvC;E0Cj1PF;IzCgLI,gByCsM8D;E1C89OhE;E0Cp1PF;IAmXQ,UAAU;IACV,gBAAiC;E1Co+OvC;E0Cx1PF;IzCgLI,sByCsM8D;E1Cq+OhE;E0C31PF;IAmXQ,UAAU;IACV,gBAAiC;E1C2+OvC;E0C/1PF;IzCgLI,sByCsM8D;E1C4+OhE;E0Cl2PF;IAmXQ,UAAU;IACV,UAAiC;E1Ck/OvC;E0Ct2PF;IzCgLI,gByCsM8D;E1Cm/OhE;E0Cz2PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cy/OvC;E0C72PF;IzCgLI,sByCsM8D;E1C0/OhE;E0Ch3PF;IAmXQ,UAAU;IACV,gBAAiC;E1CggPvC;E0Cp3PF;IzCgLI,sByCsM8D;E1CigPhE;E0Cv3PF;IAmXQ,UAAU;IACV,UAAiC;E1CugPvC;E0C33PF;IzCgLI,gByCsM8D;E1CwgPhE;E0C93PF;IAmXQ,UAAU;IACV,gBAAiC;E1C8gPvC;E0Cl4PF;IzCgLI,sByCsM8D;E1C+gPhE;E0Cr4PF;IAmXQ,UAAU;IACV,gBAAiC;E1CqhPvC;E0Cz4PF;IzCgLI,sByCsM8D;E1CshPhE;E0C54PF;IAmXQ,UAAU;IACV,WAAiC;E1C4hPvC;E0Ch5PF;IzCgLI,iByCsM8D;E1C6hPhE;AACF;;ACpwPI;EyChJJ;IAyXM,UAAU;IACV,YAAY;E1CgiPhB;E0C15PF;IA4XM,UAAU;IACV,WAAW;E1CiiPf;E0C95PF;IA+XM,UAAU;IACV,UAAU;E1CkiPd;E0Cl6PF;IAkYM,UAAU;IACV,eAAe;E1CmiPnB;E0Ct6PF;IAqYM,UAAU;IACV,UAAU;E1CoiPd;E0C16PF;IAwYM,UAAU;IACV,eAAe;E1CqiPnB;E0C96PF;IA2YM,UAAU;IACV,UAAU;E1CsiPd;E0Cl7PF;IA8YM,UAAU;IACV,UAAU;E1CuiPd;E0Ct7PF;IAiZM,UAAU;IACV,UAAU;E1CwiPd;E0C17PF;IAoZM,UAAU;IACV,UAAU;E1CyiPd;E0C97PF;IAuZM,UAAU;IACV,UAAU;E1C0iPd;E0Cl8PF;IzCgLI,gByC0OqC;E1C2iPvC;E0Cr8PF;IzCgLI,qByC4O0C;E1C4iP5C;E0Cx8PF;IzCgLI,gByC8OqC;E1C6iPvC;E0C38PF;IzCgLI,qByCgP0C;E1C8iP5C;E0C98PF;IzCgLI,gByCkPqC;E1C+iPvC;E0Cj9PF;IzCgLI,gByCoPqC;E1CgjPvC;E0Cp9PF;IzCgLI,gByCsPqC;E1CijPvC;E0Cv9PF;IzCgLI,gByCwPqC;E1CkjPvC;E0C19PF;IzCgLI,gByC0PqC;E1CmjPvC;E0C79PF;IA6aQ,UAAU;IACV,SAAiC;E1CmjPvC;E0Cj+PF;IzCgLI,eyCgQ8D;E1CojPhE;E0Cp+PF;IA6aQ,UAAU;IACV,eAAiC;E1C0jPvC;E0Cx+PF;IzCgLI,qByCgQ8D;E1C2jPhE;E0C3+PF;IA6aQ,UAAU;IACV,gBAAiC;E1CikPvC;E0C/+PF;IzCgLI,sByCgQ8D;E1CkkPhE;E0Cl/PF;IA6aQ,UAAU;IACV,UAAiC;E1CwkPvC;E0Ct/PF;IzCgLI,gByCgQ8D;E1CykPhE;E0Cz/PF;IA6aQ,UAAU;IACV,gBAAiC;E1C+kPvC;E0C7/PF;IzCgLI,sByCgQ8D;E1CglPhE;E0ChgQF;IA6aQ,UAAU;IACV,gBAAiC;E1CslPvC;E0CpgQF;IzCgLI,sByCgQ8D;E1CulPhE;E0CvgQF;IA6aQ,UAAU;IACV,UAAiC;E1C6lPvC;E0C3gQF;IzCgLI,gByCgQ8D;E1C8lPhE;E0C9gQF;IA6aQ,UAAU;IACV,gBAAiC;E1ComPvC;E0ClhQF;IzCgLI,sByCgQ8D;E1CqmPhE;E0CrhQF;IA6aQ,UAAU;IACV,gBAAiC;E1C2mPvC;E0CzhQF;IzCgLI,sByCgQ8D;E1C4mPhE;E0C5hQF;IA6aQ,UAAU;IACV,UAAiC;E1CknPvC;E0ChiQF;IzCgLI,gByCgQ8D;E1CmnPhE;E0CniQF;IA6aQ,UAAU;IACV,gBAAiC;E1CynPvC;E0CviQF;IzCgLI,sByCgQ8D;E1C0nPhE;E0C1iQF;IA6aQ,UAAU;IACV,gBAAiC;E1CgoPvC;E0C9iQF;IzCgLI,sByCgQ8D;E1CioPhE;E0CjjQF;IA6aQ,UAAU;IACV,WAAiC;E1CuoPvC;E0CrjQF;IzCgLI,iByCgQ8D;E1CwoPhE;AACF;;A0CvoPA;EzClQI,qByClLgB;EzCkLhB,sByClLgB;EAublB,oBAvbkB;A1CikQpB;;A0C7oPA;EAKI,uBAzbgB;A1CqkQpB;;A0CjpPA;EAOI,qCAA4C;A1C8oPhD;;A0CrpPA;EAUI,uBAAuB;A1C+oP3B;;A0CzpPA;EzClQI,cyC8QiC;EzC9QjC,eyC+QiC;EACjC,aAAa;A1CipPjB;;A0C/pPA;EAgBM,SAAS;EACT,qBAAqB;A1CmpP3B;;A0CpqPA;EAmBM,qBAAqB;A1CqpP3B;;A0CxqPA;EAqBM,gBAAgB;A1CupPtB;;A0C5qPA;EAuBI,aAAa;A1CypPjB;;A0ChrPA;EAyBI,eAAe;A1C2pPnB;;A0CprPA;EA2BI,mBAAmB;A1C6pPvB;;ACpgQE;EyC4UF;IA+BM,aAAa;E1C8pPjB;AACF;;AC9/PE;EyCgUF;IAmCM,aAAa;E1CgqPjB;AACF;;A0C9pPE;EACE,oBAAY;EzCzSZ,wCyC0S2D;EzC1S3D,yCyC2S2D;A1CiqP/D;;A0CpqPE;EAKI,8BAA8B;EAC9B,+BAA+B;A1CmqPrC;;A0CzqPE;EASM,iBAAY;A1CoqPpB;;ACniQE;EyCsXA;IAYQ,iBAAY;E1CsqPpB;AACF;;ACriQE;EyCkXA;IAeQ,iBAAY;E1CyqPpB;AACF;;ACviQE;EyC8WA;IAkBQ,iBAAY;E1C4qPpB;AACF;;ACziQE;EyC0WA;IAqBQ,iBAAY;E1C+qPpB;AACF;;AC3iQE;EyCsWA;IAwBQ,iBAAY;E1CkrPpB;AACF;;AC5iQI;EyCiWF;IA2BQ,iBAAY;E1CqrPpB;AACF;;ACxiQI;EyCuVF;IA8BQ,iBAAY;E1CwrPpB;AACF;;ACziQI;EyCkVF;IAiCQ,iBAAY;E1C2rPpB;AACF;;ACriQI;EyCwUF;IAoCQ,iBAAY;E1C8rPpB;AACF;;A0CnuPE;EASM,oBAAY;A1C8tPpB;;AC7lQE;EyCsXA;IAYQ,oBAAY;E1CguPpB;AACF;;AC/lQE;EyCkXA;IAeQ,oBAAY;E1CmuPpB;AACF;;ACjmQE;EyC8WA;IAkBQ,oBAAY;E1CsuPpB;AACF;;ACnmQE;EyC0WA;IAqBQ,oBAAY;E1CyuPpB;AACF;;ACrmQE;EyCsWA;IAwBQ,oBAAY;E1C4uPpB;AACF;;ACtmQI;EyCiWF;IA2BQ,oBAAY;E1C+uPpB;AACF;;AClmQI;EyCuVF;IA8BQ,oBAAY;E1CkvPpB;AACF;;ACnmQI;EyCkVF;IAiCQ,oBAAY;E1CqvPpB;AACF;;AC/lQI;EyCwUF;IAoCQ,oBAAY;E1CwvPpB;AACF;;A0C7xPE;EASM,mBAAY;A1CwxPpB;;ACvpQE;EyCsXA;IAYQ,mBAAY;E1C0xPpB;AACF;;ACzpQE;EyCkXA;IAeQ,mBAAY;E1C6xPpB;AACF;;AC3pQE;EyC8WA;IAkBQ,mBAAY;E1CgyPpB;AACF;;AC7pQE;EyC0WA;IAqBQ,mBAAY;E1CmyPpB;AACF;;AC/pQE;EyCsWA;IAwBQ,mBAAY;E1CsyPpB;AACF;;AChqQI;EyCiWF;IA2BQ,mBAAY;E1CyyPpB;AACF;;AC5pQI;EyCuVF;IA8BQ,mBAAY;E1C4yPpB;AACF;;AC7pQI;EyCkVF;IAiCQ,mBAAY;E1C+yPpB;AACF;;ACzpQI;EyCwUF;IAoCQ,mBAAY;E1CkzPpB;AACF;;A0Cv1PE;EASM,oBAAY;A1Ck1PpB;;ACjtQE;EyCsXA;IAYQ,oBAAY;E1Co1PpB;AACF;;ACntQE;EyCkXA;IAeQ,oBAAY;E1Cu1PpB;AACF;;ACrtQE;EyC8WA;IAkBQ,oBAAY;E1C01PpB;AACF;;ACvtQE;EyC0WA;IAqBQ,oBAAY;E1C61PpB;AACF;;ACztQE;EyCsWA;IAwBQ,oBAAY;E1Cg2PpB;AACF;;AC1tQI;EyCiWF;IA2BQ,oBAAY;E1Cm2PpB;AACF;;ACttQI;EyCuVF;IA8BQ,oBAAY;E1Cs2PpB;AACF;;ACvtQI;EyCkVF;IAiCQ,oBAAY;E1Cy2PpB;AACF;;ACntQI;EyCwUF;IAoCQ,oBAAY;E1C42PpB;AACF;;A0Cj5PE;EASM,iBAAY;A1C44PpB;;AC3wQE;EyCsXA;IAYQ,iBAAY;E1C84PpB;AACF;;AC7wQE;EyCkXA;IAeQ,iBAAY;E1Ci5PpB;AACF;;AC/wQE;EyC8WA;IAkBQ,iBAAY;E1Co5PpB;AACF;;ACjxQE;EyC0WA;IAqBQ,iBAAY;E1Cu5PpB;AACF;;ACnxQE;EyCsWA;IAwBQ,iBAAY;E1C05PpB;AACF;;ACpxQI;EyCiWF;IA2BQ,iBAAY;E1C65PpB;AACF;;AChxQI;EyCuVF;IA8BQ,iBAAY;E1Cg6PpB;AACF;;ACjxQI;EyCkVF;IAiCQ,iBAAY;E1Cm6PpB;AACF;;AC7wQI;EyCwUF;IAoCQ,iBAAY;E1Cs6PpB;AACF;;A0C38PE;EASM,oBAAY;A1Cs8PpB;;ACr0QE;EyCsXA;IAYQ,oBAAY;E1Cw8PpB;AACF;;ACv0QE;EyCkXA;IAeQ,oBAAY;E1C28PpB;AACF;;ACz0QE;EyC8WA;IAkBQ,oBAAY;E1C88PpB;AACF;;AC30QE;EyC0WA;IAqBQ,oBAAY;E1Ci9PpB;AACF;;AC70QE;EyCsWA;IAwBQ,oBAAY;E1Co9PpB;AACF;;AC90QI;EyCiWF;IA2BQ,oBAAY;E1Cu9PpB;AACF;;AC10QI;EyCuVF;IA8BQ,oBAAY;E1C09PpB;AACF;;AC30QI;EyCkVF;IAiCQ,oBAAY;E1C69PpB;AACF;;ACv0QI;EyCwUF;IAoCQ,oBAAY;E1Cg+PpB;AACF;;A0CrgQE;EASM,mBAAY;A1CggQpB;;AC/3QE;EyCsXA;IAYQ,mBAAY;E1CkgQpB;AACF;;ACj4QE;EyCkXA;IAeQ,mBAAY;E1CqgQpB;AACF;;ACn4QE;EyC8WA;IAkBQ,mBAAY;E1CwgQpB;AACF;;ACr4QE;EyC0WA;IAqBQ,mBAAY;E1C2gQpB;AACF;;ACv4QE;EyCsWA;IAwBQ,mBAAY;E1C8gQpB;AACF;;ACx4QI;EyCiWF;IA2BQ,mBAAY;E1CihQpB;AACF;;ACp4QI;EyCuVF;IA8BQ,mBAAY;E1CohQpB;AACF;;ACr4QI;EyCkVF;IAiCQ,mBAAY;E1CuhQpB;AACF;;ACj4QI;EyCwUF;IAoCQ,mBAAY;E1C0hQpB;AACF;;A0C/jQE;EASM,oBAAY;A1C0jQpB;;ACz7QE;EyCsXA;IAYQ,oBAAY;E1C4jQpB;AACF;;AC37QE;EyCkXA;IAeQ,oBAAY;E1C+jQpB;AACF;;AC77QE;EyC8WA;IAkBQ,oBAAY;E1CkkQpB;AACF;;AC/7QE;EyC0WA;IAqBQ,oBAAY;E1CqkQpB;AACF;;ACj8QE;EyCsWA;IAwBQ,oBAAY;E1CwkQpB;AACF;;ACl8QI;EyCiWF;IA2BQ,oBAAY;E1C2kQpB;AACF;;AC97QI;EyCuVF;IA8BQ,oBAAY;E1C8kQpB;AACF;;AC/7QI;EyCkVF;IAiCQ,oBAAY;E1CilQpB;AACF;;AC37QI;EyCwUF;IAoCQ,oBAAY;E1ColQpB;AACF;;A0CznQE;EASM,iBAAY;A1ConQpB;;ACn/QE;EyCsXA;IAYQ,iBAAY;E1CsnQpB;AACF;;ACr/QE;EyCkXA;IAeQ,iBAAY;E1CynQpB;AACF;;ACv/QE;EyC8WA;IAkBQ,iBAAY;E1C4nQpB;AACF;;ACz/QE;EyC0WA;IAqBQ,iBAAY;E1C+nQpB;AACF;;AC3/QE;EyCsWA;IAwBQ,iBAAY;E1CkoQpB;AACF;;AC5/QI;EyCiWF;IA2BQ,iBAAY;E1CqoQpB;AACF;;ACx/QI;EyCuVF;IA8BQ,iBAAY;E1CwoQpB;AACF;;ACz/QI;EyCkVF;IAiCQ,iBAAY;E1C2oQpB;AACF;;ACr/QI;EyCwUF;IAoCQ,iBAAY;E1C8oQpB;AACF;;A2C3oRA;EACE,oBAAoB;EACpB,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,+BAAuB;EAAvB,4BAAuB;EAAvB,uBAAuB;A3C8oRzB;;A2CppRA;EASI,qBAA+B;EAC/B,sBAAgC;EAChC,oBAA8B;A3C+oRlC;;A2C1pRA;EAaM,uBAAiC;A3CipRvC;;A2C9pRA;EAeM,sBAjBgB;A3CoqRtB;;A2ClqRA;EAiBI,oBAAoB;A3CqpRxB;;A2CtqRA;EAmBI,gBArBkB;A3C4qRtB;;A2C1qRA;EAqBI,sBAAsB;A3CypR1B;;A2C9qRA;EAuBM,gCAAgC;A3C2pRtC;;AC5kRE;E0CtGF;IA2BM,aAAa;E3C4pRjB;E2CvrRF;IA8BQ,UAAU;IACV,eAA8B;E3C4pRpC;E2C3rRF;IA8BQ,UAAU;IACV,gBAA8B;E3CgqRpC;E2C/rRF;IA8BQ,UAAU;IACV,UAA8B;E3CoqRpC;E2CnsRF;IA8BQ,UAAU;IACV,gBAA8B;E3CwqRpC;E2CvsRF;IA8BQ,UAAU;IACV,gBAA8B;E3C4qRpC;E2C3sRF;IA8BQ,UAAU;IACV,UAA8B;E3CgrRpC;E2C/sRF;IA8BQ,UAAU;IACV,gBAA8B;E3CorRpC;E2CntRF;IA8BQ,UAAU;IACV,gBAA8B;E3CwrRpC;E2CvtRF;IA8BQ,UAAU;IACV,UAA8B;E3C4rRpC;E2C3tRF;IA8BQ,UAAU;IACV,gBAA8B;E3CgsRpC;E2C/tRF;IA8BQ,UAAU;IACV,gBAA8B;E3CosRpC;E2CnuRF;IA8BQ,UAAU;IACV,WAA8B;E3CwsRpC;AACF;;A4C5uRA,kBAAA;ACIE;EACE,uBAAwB;A7C4uR5B;;A6C3uRE;EAGI,yBAA0C;A7C4uRhD;;A6C3uRE;EACE,kCAAmC;A7C8uRvC;;A6CrvRE;EACE,yBAAwB;A7CwvR5B;;A6CvvRE;EAGI,uBAA0C;A7CwvRhD;;A6CvvRE;EACE,oCAAmC;A7C0vRvC;;A6CjwRE;EACE,4BAAwB;A7CowR5B;;A6CnwRE;EAGI,yBAA0C;A7CowRhD;;A6CnwRE;EACE,uCAAmC;A7CswRvC;;A6C7wRE;EACE,yBAAwB;A7CgxR5B;;A6C/wRE;EAGI,yBAA0C;A7CgxRhD;;A6C/wRE;EACE,oCAAmC;A7CkxRvC;;A6CzxRE;EACE,yBAAwB;A7C4xR5B;;A6C3xRE;EAGI,yBAA0C;A7C4xRhD;;A6C3xRE;EACE,oCAAmC;A7C8xRvC;;A6CzxRI;EACE,yBAA8B;A7C4xRpC;;A6C3xRI;EAGI,yBAAgD;A7C4xRxD;;A6C3xRI;EACE,oCAAyC;A7C8xR/C;;A6C5xRI;EACE,yBAA6B;A7C+xRnC;;A6C9xRI;EAGI,yBAAgD;A7C+xRxD;;A6C9xRI;EACE,oCAAwC;A7CiyR9C;;A6C7zRE;EACE,yBAAwB;A7Cg0R5B;;A6C/zRE;EAGI,yBAA0C;A7Cg0RhD;;A6C/zRE;EACE,oCAAmC;A7Ck0RvC;;A6C7zRI;EACE,yBAA8B;A7Cg0RpC;;A6C/zRI;EAGI,yBAAgD;A7Cg0RxD;;A6C/zRI;EACE,oCAAyC;A7Ck0R/C;;A6Ch0RI;EACE,yBAA6B;A7Cm0RnC;;A6Cl0RI;EAGI,yBAAgD;A7Cm0RxD;;A6Cl0RI;EACE,oCAAwC;A7Cq0R9C;;A6Cj2RE;EACE,yBAAwB;A7Co2R5B;;A6Cn2RE;EAGI,yBAA0C;A7Co2RhD;;A6Cn2RE;EACE,oCAAmC;A7Cs2RvC;;A6Cj2RI;EACE,yBAA8B;A7Co2RpC;;A6Cn2RI;EAGI,yBAAgD;A7Co2RxD;;A6Cn2RI;EACE,oCAAyC;A7Cs2R/C;;A6Cp2RI;EACE,yBAA6B;A7Cu2RnC;;A6Ct2RI;EAGI,yBAAgD;A7Cu2RxD;;A6Ct2RI;EACE,oCAAwC;A7Cy2R9C;;A6Cr4RE;EACE,yBAAwB;A7Cw4R5B;;A6Cv4RE;EAGI,yBAA0C;A7Cw4RhD;;A6Cv4RE;EACE,oCAAmC;A7C04RvC;;A6Cr4RI;EACE,yBAA8B;A7Cw4RpC;;A6Cv4RI;EAGI,yBAAgD;A7Cw4RxD;;A6Cv4RI;EACE,oCAAyC;A7C04R/C;;A6Cx4RI;EACE,yBAA6B;A7C24RnC;;A6C14RI;EAGI,yBAAgD;A7C24RxD;;A6C14RI;EACE,oCAAwC;A7C64R9C;;A6Cz6RE;EACE,yBAAwB;A7C46R5B;;A6C36RE;EAGI,yBAA0C;A7C46RhD;;A6C36RE;EACE,oCAAmC;A7C86RvC;;A6Cz6RI;EACE,yBAA8B;A7C46RpC;;A6C36RI;EAGI,yBAAgD;A7C46RxD;;A6C36RI;EACE,oCAAyC;A7C86R/C;;A6C56RI;EACE,yBAA6B;A7C+6RnC;;A6C96RI;EAGI,yBAAgD;A7C+6RxD;;A6C96RI;EACE,oCAAwC;A7Ci7R9C;;A6C78RE;EACE,yBAAwB;A7Cg9R5B;;A6C/8RE;EAGI,yBAA0C;A7Cg9RhD;;A6C/8RE;EACE,oCAAmC;A7Ck9RvC;;A6C78RI;EACE,yBAA8B;A7Cg9RpC;;A6C/8RI;EAGI,yBAAgD;A7Cg9RxD;;A6C/8RI;EACE,oCAAyC;A7Ck9R/C;;A6Ch9RI;EACE,yBAA6B;A7Cm9RnC;;A6Cl9RI;EAGI,yBAAgD;A7Cm9RxD;;A6Cl9RI;EACE,oCAAwC;A7Cq9R9C;;A6Cl9RE;EACE,yBAAwB;A7Cq9R5B;;A6Cp9RE;EACE,oCAAmC;A7Cu9RvC;;A6C19RE;EACE,yBAAwB;A7C69R5B;;A6C59RE;EACE,oCAAmC;A7C+9RvC;;A6Cl+RE;EACE,yBAAwB;A7Cq+R5B;;A6Cp+RE;EACE,oCAAmC;A7Cu+RvC;;A6C1+RE;EACE,yBAAwB;A7C6+R5B;;A6C5+RE;EACE,oCAAmC;A7C++RvC;;A6Cl/RE;EACE,yBAAwB;A7Cq/R5B;;A6Cp/RE;EACE,oCAAmC;A7Cu/RvC;;A6C1/RE;EACE,yBAAwB;A7C6/R5B;;A6C5/RE;EACE,oCAAmC;A7C+/RvC;;A6ClgSE;EACE,yBAAwB;A7CqgS5B;;A6CpgSE;EACE,oCAAmC;A7CugSvC;;A6C1gSE;EACE,4BAAwB;A7C6gS5B;;A6C5gSE;EACE,uCAAmC;A7C+gSvC;;A6ClhSE;EACE,yBAAwB;A7CqhS5B;;A6CphSE;EACE,oCAAmC;A7CuhSvC;;A8C3jSE;EACE,8BAAiC;A9C8jSrC;;A8C/jSE;EACE,sCAAiC;A9CkkSrC;;A8CnkSE;EACE,iCAAiC;A9CskSrC;;A8CvkSE;EACE,yCAAiC;A9C0kSrC;;A8CtkSE;EACE,4BAA4B;A9CykShC;;A8C1kSE;EACE,0BAA4B;A9C6kShC;;A8C9kSE;EACE,kCAA4B;A9CilShC;;A8C7kSE;EACE,sCAAkC;A9CglStC;;A8CjlSE;EACE,oCAAkC;A9ColStC;;A8CrlSE;EACE,kCAAkC;A9CwlStC;;A8CzlSE;EACE,yCAAkC;A9C4lStC;;A8C7lSE;EACE,wCAAkC;A9CgmStC;;A8CjmSE;EACE,wCAAkC;A9ComStC;;A8CrmSE;EACE,iCAAkC;A9CwmStC;;A8CzmSE;EACE,+BAAkC;A9C4mStC;;A8C7mSE;EACE,gCAAkC;A9CgnStC;;A8CjnSE;EACE,iCAAkC;A9ConStC;;A8ChnSE;EACE,oCAAgC;A9CmnSpC;;A8CpnSE;EACE,kCAAgC;A9CunSpC;;A8CxnSE;EACE,gCAAgC;A9C2nSpC;;A8C5nSE;EACE,uCAAgC;A9C+nSpC;;A8ChoSE;EACE,sCAAgC;A9CmoSpC;;A8CpoSE;EACE,sCAAgC;A9CuoSpC;;A8CxoSE;EACE,iCAAgC;A9C2oSpC;;A8C5oSE;EACE,+BAAgC;A9C+oSpC;;A8ChpSE;EACE,6BAAgC;A9CmpSpC;;A8CppSE;EACE,kCAAgC;A9CupSpC;;A8CnpSE;EACE,+BAA8B;A9CspSlC;;A8CvpSE;EACE,kCAA8B;A9C0pSlC;;A8C3pSE;EACE,gCAA8B;A9C8pSlC;;A8C/pSE;EACE,8BAA8B;A9CkqSlC;;A8CnqSE;EACE,gCAA8B;A9CsqSlC;;A8CvqSE;EACE,6BAA8B;A9C0qSlC;;A8C3qSE;EACE,2BAA8B;A9C8qSlC;;A8C/qSE;EACE,kCAA8B;A9CkrSlC;;A8CnrSE;EACE,gCAA8B;A9CsrSlC;;A8ClrSE;EACE,2BAA6B;A9CqrSjC;;A8CtrSE;EACE,iCAA6B;A9CyrSjC;;A8C1rSE;EACE,+BAA6B;A9C6rSjC;;A8C9rSE;EACE,6BAA6B;A9CisSjC;;A8ClsSE;EACE,+BAA6B;A9CqsSjC;;A8CtsSE;EACE,8BAA6B;A9CysSjC;;A8CpsSI;EACE,uBAAqC;A9CusS3C;;A8CxsSI;EACE,uBAAqC;A9C2sS3C;;A8C5sSI;EACE,uBAAqC;A9C+sS3C;;A8ChtSI;EACE,uBAAqC;A9CmtS3C;;A8CptSI;EACE,uBAAqC;A9CutS3C;;A8CxtSI;EACE,uBAAqC;A9C2tS3C;;A8C5tSI;EACE,yBAAqC;A9C+tS3C;;A8ChuSI;EACE,yBAAqC;A9CmuS3C;;A8CpuSI;EACE,yBAAqC;A9CuuS3C;;A8CxuSI;EACE,yBAAqC;A9C2uS3C;;A8C5uSI;EACE,yBAAqC;A9C+uS3C;;A8ChvSI;EACE,yBAAqC;A9CmvS3C;;AClxSE;EACE,WAAW;EACX,YAAY;EACZ,cAAc;ADqxSlB;;A+CtxSA;EACE,sBAAsB;A/CyxSxB;;A+CvxSA;EACE,uBAAuB;A/C0xSzB;;AgDjySA;EACE,2BAA2B;AhDoyS7B;;AgDlySA;EACE,2BAA2B;AhDqyS7B;;AgDnySA;EACE,0BAA0B;EAC1B,8BAA8B;AhDsyShC;;AiDhzSA;EACE,2BAA2B;AjDmzS7B;;AkD/ySA;EACE,6BAA6B;AlDkzS/B;;AmDxzSA;EACE,oBAAoB;AnD2zStB;;AmDzzSA;EACE,qBAAqB;AnD4zSvB;;AmDjzSI;EACE,oBAA+B;AnDozSrC;;AmDjzSM;EACE,wBAA8C;AnDozStD;;AmDrzSM;EACE,0BAA8C;AnDwzStD;;AmDzzSM;EACE,2BAA8C;AnD4zStD;;AmD7zSM;EACE,yBAA8C;AnDg0StD;;AmD7zSM;EACE,yBAAyC;EACzC,0BAA2C;AnDg0SnD;;AmD7zSM;EACE,wBAAuC;EACvC,2BAA6C;AnDg0SrD;;AmD/0SI;EACE,0BAA+B;AnDk1SrC;;AmD/0SM;EACE,8BAA8C;AnDk1StD;;AmDn1SM;EACE,gCAA8C;AnDs1StD;;AmDv1SM;EACE,iCAA8C;AnD01StD;;AmD31SM;EACE,+BAA8C;AnD81StD;;AmD31SM;EACE,+BAAyC;EACzC,gCAA2C;AnD81SnD;;AmD31SM;EACE,8BAAuC;EACvC,iCAA6C;AnD81SrD;;AmD72SI;EACE,yBAA+B;AnDg3SrC;;AmD72SM;EACE,6BAA8C;AnDg3StD;;AmDj3SM;EACE,+BAA8C;AnDo3StD;;AmDr3SM;EACE,gCAA8C;AnDw3StD;;AmDz3SM;EACE,8BAA8C;AnD43StD;;AmDz3SM;EACE,8BAAyC;EACzC,+BAA2C;AnD43SnD;;AmDz3SM;EACE,6BAAuC;EACvC,gCAA6C;AnD43SrD;;AmD34SI;EACE,0BAA+B;AnD84SrC;;AmD34SM;EACE,8BAA8C;AnD84StD;;AmD/4SM;EACE,gCAA8C;AnDk5StD;;AmDn5SM;EACE,iCAA8C;AnDs5StD;;AmDv5SM;EACE,+BAA8C;AnD05StD;;AmDv5SM;EACE,+BAAyC;EACzC,gCAA2C;AnD05SnD;;AmDv5SM;EACE,8BAAuC;EACvC,iCAA6C;AnD05SrD;;AmDz6SI;EACE,uBAA+B;AnD46SrC;;AmDz6SM;EACE,2BAA8C;AnD46StD;;AmD76SM;EACE,6BAA8C;AnDg7StD;;AmDj7SM;EACE,8BAA8C;AnDo7StD;;AmDr7SM;EACE,4BAA8C;AnDw7StD;;AmDr7SM;EACE,4BAAyC;EACzC,6BAA2C;AnDw7SnD;;AmDr7SM;EACE,2BAAuC;EACvC,8BAA6C;AnDw7SrD;;AmDv8SI;EACE,yBAA+B;AnD08SrC;;AmDv8SM;EACE,6BAA8C;AnD08StD;;AmD38SM;EACE,+BAA8C;AnD88StD;;AmD/8SM;EACE,gCAA8C;AnDk9StD;;AmDn9SM;EACE,8BAA8C;AnDs9StD;;AmDn9SM;EACE,8BAAyC;EACzC,+BAA2C;AnDs9SnD;;AmDn9SM;EACE,6BAAuC;EACvC,gCAA6C;AnDs9SrD;;AmDr+SI;EACE,uBAA+B;AnDw+SrC;;AmDr+SM;EACE,2BAA8C;AnDw+StD;;AmDz+SM;EACE,6BAA8C;AnD4+StD;;AmD7+SM;EACE,8BAA8C;AnDg/StD;;AmDj/SM;EACE,4BAA8C;AnDo/StD;;AmDj/SM;EACE,4BAAyC;EACzC,6BAA2C;AnDo/SnD;;AmDj/SM;EACE,2BAAuC;EACvC,8BAA6C;AnDo/SrD;;AmDngTI;EACE,uBAA+B;AnDsgTrC;;AmDngTM;EACE,2BAA8C;AnDsgTtD;;AmDvgTM;EACE,6BAA8C;AnD0gTtD;;AmD3gTM;EACE,8BAA8C;AnD8gTtD;;AmD/gTM;EACE,4BAA8C;AnDkhTtD;;AmD/gTM;EACE,4BAAyC;EACzC,6BAA2C;AnDkhTnD;;AmD/gTM;EACE,2BAAuC;EACvC,8BAA6C;AnDkhTrD;;AmDjiTI;EACE,qBAA+B;AnDoiTrC;;AmDjiTM;EACE,yBAA8C;AnDoiTtD;;AmDriTM;EACE,2BAA8C;AnDwiTtD;;AmDziTM;EACE,4BAA8C;AnD4iTtD;;AmD7iTM;EACE,0BAA8C;AnDgjTtD;;AmD7iTM;EACE,0BAAyC;EACzC,2BAA2C;AnDgjTnD;;AmD7iTM;EACE,yBAAuC;EACvC,4BAA6C;AnDgjTrD;;AmD/jTI;EACE,2BAA+B;AnDkkTrC;;AmD/jTM;EACE,+BAA8C;AnDkkTtD;;AmDnkTM;EACE,iCAA8C;AnDskTtD;;AmDvkTM;EACE,kCAA8C;AnD0kTtD;;AmD3kTM;EACE,gCAA8C;AnD8kTtD;;AmD3kTM;EACE,gCAAyC;EACzC,iCAA2C;AnD8kTnD;;AmD3kTM;EACE,+BAAuC;EACvC,kCAA6C;AnD8kTrD;;AmD7lTI;EACE,0BAA+B;AnDgmTrC;;AmD7lTM;EACE,8BAA8C;AnDgmTtD;;AmDjmTM;EACE,gCAA8C;AnDomTtD;;AmDrmTM;EACE,iCAA8C;AnDwmTtD;;AmDzmTM;EACE,+BAA8C;AnD4mTtD;;AmDzmTM;EACE,+BAAyC;EACzC,gCAA2C;AnD4mTnD;;AmDzmTM;EACE,8BAAuC;EACvC,iCAA6C;AnD4mTrD;;AmD3nTI;EACE,2BAA+B;AnD8nTrC;;AmD3nTM;EACE,+BAA8C;AnD8nTtD;;AmD/nTM;EACE,iCAA8C;AnDkoTtD;;AmDnoTM;EACE,kCAA8C;AnDsoTtD;;AmDvoTM;EACE,gCAA8C;AnD0oTtD;;AmDvoTM;EACE,gCAAyC;EACzC,iCAA2C;AnD0oTnD;;AmDvoTM;EACE,+BAAuC;EACvC,kCAA6C;AnD0oTrD;;AmDzpTI;EACE,wBAA+B;AnD4pTrC;;AmDzpTM;EACE,4BAA8C;AnD4pTtD;;AmD7pTM;EACE,8BAA8C;AnDgqTtD;;AmDjqTM;EACE,+BAA8C;AnDoqTtD;;AmDrqTM;EACE,6BAA8C;AnDwqTtD;;AmDrqTM;EACE,6BAAyC;EACzC,8BAA2C;AnDwqTnD;;AmDrqTM;EACE,4BAAuC;EACvC,+BAA6C;AnDwqTrD;;AmDvrTI;EACE,0BAA+B;AnD0rTrC;;AmDvrTM;EACE,8BAA8C;AnD0rTtD;;AmD3rTM;EACE,gCAA8C;AnD8rTtD;;AmD/rTM;EACE,iCAA8C;AnDksTtD;;AmDnsTM;EACE,+BAA8C;AnDssTtD;;AmDnsTM;EACE,+BAAyC;EACzC,gCAA2C;AnDssTnD;;AmDnsTM;EACE,8BAAuC;EACvC,iCAA6C;AnDssTrD;;AmDrtTI;EACE,wBAA+B;AnDwtTrC;;AmDrtTM;EACE,4BAA8C;AnDwtTtD;;AmDztTM;EACE,8BAA8C;AnD4tTtD;;AmD7tTM;EACE,+BAA8C;AnDguTtD;;AmDjuTM;EACE,6BAA8C;AnDouTtD;;AmDjuTM;EACE,6BAAyC;EACzC,8BAA2C;AnDouTnD;;AmDjuTM;EACE,4BAAuC;EACvC,+BAA6C;AnDouTrD;;AmDnvTI;EACE,wBAA+B;AnDsvTrC;;AmDnvTM;EACE,4BAA8C;AnDsvTtD;;AmDvvTM;EACE,8BAA8C;AnD0vTtD;;AmD3vTM;EACE,+BAA8C;AnD8vTtD;;AmD/vTM;EACE,6BAA8C;AnDkwTtD;;AmD/vTM;EACE,6BAAyC;EACzC,8BAA2C;AnDkwTnD;;AmD/vTM;EACE,4BAAuC;EACvC,+BAA6C;AnDkwTrD;;AoD3xTI;EACE,0BAA2B;ApD8xTjC;;AoD/xTI;EACE,4BAA2B;ApDkyTjC;;AoDnyTI;EACE,0BAA2B;ApDsyTjC;;AoDvyTI;EACE,4BAA2B;ApD0yTjC;;AoD3yTI;EACE,6BAA2B;ApD8yTjC;;AoD/yTI;EACE,0BAA2B;ApDkzTjC;;AoDnzTI;EACE,6BAA2B;ApDszTjC;;ACttTE;EmDjGE;IACE,0BAA2B;EpD2zT/B;EoD5zTE;IACE,4BAA2B;EpD8zT/B;EoD/zTE;IACE,0BAA2B;EpDi0T/B;EoDl0TE;IACE,4BAA2B;EpDo0T/B;EoDr0TE;IACE,6BAA2B;EpDu0T/B;EoDx0TE;IACE,0BAA2B;EpD00T/B;EoD30TE;IACE,6BAA2B;EpD60T/B;AACF;;AC1uTE;EmDrGE;IACE,0BAA2B;EpDm1T/B;EoDp1TE;IACE,4BAA2B;EpDs1T/B;EoDv1TE;IACE,0BAA2B;EpDy1T/B;EoD11TE;IACE,4BAA2B;EpD41T/B;EoD71TE;IACE,6BAA2B;EpD+1T/B;EoDh2TE;IACE,0BAA2B;EpDk2T/B;EoDn2TE;IACE,6BAA2B;EpDq2T/B;AACF;;AC1vTE;EmD7GE;IACE,0BAA2B;EpD22T/B;EoD52TE;IACE,4BAA2B;EpD82T/B;EoD/2TE;IACE,0BAA2B;EpDi3T/B;EoDl3TE;IACE,4BAA2B;EpDo3T/B;EoDr3TE;IACE,6BAA2B;EpDu3T/B;EoDx3TE;IACE,0BAA2B;EpD03T/B;EoD33TE;IACE,6BAA2B;EpD63T/B;AACF;;AC9wTE;EmDjHE;IACE,0BAA2B;EpDm4T/B;EoDp4TE;IACE,4BAA2B;EpDs4T/B;EoDv4TE;IACE,0BAA2B;EpDy4T/B;EoD14TE;IACE,4BAA2B;EpD44T/B;EoD74TE;IACE,6BAA2B;EpD+4T/B;EoDh5TE;IACE,0BAA2B;EpDk5T/B;EoDn5TE;IACE,6BAA2B;EpDq5T/B;AACF;;ACvxTI;EmDhIA;IACE,0BAA2B;EpD25T/B;EoD55TE;IACE,4BAA2B;EpD85T/B;EoD/5TE;IACE,0BAA2B;EpDi6T/B;EoDl6TE;IACE,4BAA2B;EpDo6T/B;EoDr6TE;IACE,6BAA2B;EpDu6T/B;EoDx6TE;IACE,0BAA2B;EpD06T/B;EoD36TE;IACE,6BAA2B;EpD66T/B;AACF;;AChyTI;EmD/IA;IACE,0BAA2B;EpDm7T/B;EoDp7TE;IACE,4BAA2B;EpDs7T/B;EoDv7TE;IACE,0BAA2B;EpDy7T/B;EoD17TE;IACE,4BAA2B;EpD47T/B;EoD77TE;IACE,6BAA2B;EpD+7T/B;EoDh8TE;IACE,0BAA2B;EpDk8T/B;EoDn8TE;IACE,6BAA2B;EpDq8T/B;AACF;;AoD76TE;EACE,6BAAqC;ApDg7TzC;;AoDj7TE;EACE,8BAAqC;ApDo7TzC;;AoDr7TE;EACE,2BAAqC;ApDw7TzC;;AoDz7TE;EACE,4BAAqC;ApD47TzC;;ACt3TE;EmDlEE;IACE,6BAAqC;EpD47TzC;AACF;;ACx3TE;EmDnEE;IACE,6BAAqC;EpD+7TzC;AACF;;AC13TE;EmDpEE;IACE,6BAAqC;EpDk8TzC;AACF;;AC53TE;EmDrEE;IACE,6BAAqC;EpDq8TzC;AACF;;AC93TE;EmDtEE;IACE,6BAAqC;EpDw8TzC;AACF;;AC/3TI;EmDxEA;IACE,6BAAqC;EpD28TzC;AACF;;AC33TI;EmD/EA;IACE,6BAAqC;EpD88TzC;AACF;;AC53TI;EmDjFA;IACE,6BAAqC;EpDi9TzC;AACF;;ACx3TI;EmDxFA;IACE,6BAAqC;EpDo9TzC;AACF;;AC56TE;EmDlEE;IACE,8BAAqC;EpDk/TzC;AACF;;AC96TE;EmDnEE;IACE,8BAAqC;EpDq/TzC;AACF;;ACh7TE;EmDpEE;IACE,8BAAqC;EpDw/TzC;AACF;;ACl7TE;EmDrEE;IACE,8BAAqC;EpD2/TzC;AACF;;ACp7TE;EmDtEE;IACE,8BAAqC;EpD8/TzC;AACF;;ACr7TI;EmDxEA;IACE,8BAAqC;EpDigUzC;AACF;;ACj7TI;EmD/EA;IACE,8BAAqC;EpDogUzC;AACF;;ACl7TI;EmDjFA;IACE,8BAAqC;EpDugUzC;AACF;;AC96TI;EmDxFA;IACE,8BAAqC;EpD0gUzC;AACF;;ACl+TE;EmDlEE;IACE,2BAAqC;EpDwiUzC;AACF;;ACp+TE;EmDnEE;IACE,2BAAqC;EpD2iUzC;AACF;;ACt+TE;EmDpEE;IACE,2BAAqC;EpD8iUzC;AACF;;ACx+TE;EmDrEE;IACE,2BAAqC;EpDijUzC;AACF;;AC1+TE;EmDtEE;IACE,2BAAqC;EpDojUzC;AACF;;AC3+TI;EmDxEA;IACE,2BAAqC;EpDujUzC;AACF;;ACv+TI;EmD/EA;IACE,2BAAqC;EpD0jUzC;AACF;;ACx+TI;EmDjFA;IACE,2BAAqC;EpD6jUzC;AACF;;ACp+TI;EmDxFA;IACE,2BAAqC;EpDgkUzC;AACF;;ACxhUE;EmDlEE;IACE,4BAAqC;EpD8lUzC;AACF;;AC1hUE;EmDnEE;IACE,4BAAqC;EpDimUzC;AACF;;AC5hUE;EmDpEE;IACE,4BAAqC;EpDomUzC;AACF;;AC9hUE;EmDrEE;IACE,4BAAqC;EpDumUzC;AACF;;AChiUE;EmDtEE;IACE,4BAAqC;EpD0mUzC;AACF;;ACjiUI;EmDxEA;IACE,4BAAqC;EpD6mUzC;AACF;;AC7hUI;EmD/EA;IACE,4BAAqC;EpDgnUzC;AACF;;AC9hUI;EmDjFA;IACE,4BAAqC;EpDmnUzC;AACF;;AC1hUI;EmDxFA;IACE,4BAAqC;EpDsnUzC;AACF;;AoDrnUA;EACE,qCAAqC;ApDwnUvC;;AoDtnUA;EACE,oCAAoC;ApDynUtC;;AoDvnUA;EACE,oCAAoC;ApD0nUtC;;AoDxnUA;EACE,6BAA6B;ApD2nU/B;;AoDznUA;EACE,qCAAqC;ApD4nUvC;;AoD1nUA;EACE,2BAAqC;ApD6nUvC;;AoD5nUA;EACE,2BAAsC;ApD+nUxC;;AoD9nUA;EACE,2BAAsC;ApDioUxC;;AoDhoUA;EACE,2BAAwC;ApDmoU1C;;AoDloUA;EACE,2BAAoC;ApDqoUtC;;AoDnoUA;EACE,+LAAuC;ApDsoUzC;;AoDpoUA;EACE,+LAAyC;ApDuoU3C;;AoDroUA;EACE,+LAA0C;ApDwoU5C;;AoDtoUA;EACE,iCAAyC;ApDyoU3C;;AoDvoUA;EACE,iCAAoC;ApD0oUtC;;AqD3uUE;EACE,yBAA+B;ArD8uUnC;;AC9oUE;EoD9FE;IACE,yBAA+B;ErDgvUnC;AACF;;AChpUE;EoD/FE;IACE,yBAA+B;ErDmvUnC;AACF;;AClpUE;EoDhGE;IACE,yBAA+B;ErDsvUnC;AACF;;ACppUE;EoDjGE;IACE,yBAA+B;ErDyvUnC;AACF;;ACtpUE;EoDlGE;IACE,yBAA+B;ErD4vUnC;AACF;;ACvpUI;EoDpGA;IACE,yBAA+B;ErD+vUnC;AACF;;ACnpUI;EoD3GA;IACE,yBAA+B;ErDkwUnC;AACF;;ACppUI;EoD7GA;IACE,yBAA+B;ErDqwUnC;AACF;;AChpUI;EoDpHA;IACE,yBAA+B;ErDwwUnC;AACF;;AqDryUE;EACE,wBAA+B;ArDwyUnC;;ACxsUE;EoD9FE;IACE,wBAA+B;ErD0yUnC;AACF;;AC1sUE;EoD/FE;IACE,wBAA+B;ErD6yUnC;AACF;;AC5sUE;EoDhGE;IACE,wBAA+B;ErDgzUnC;AACF;;AC9sUE;EoDjGE;IACE,wBAA+B;ErDmzUnC;AACF;;AChtUE;EoDlGE;IACE,wBAA+B;ErDszUnC;AACF;;ACjtUI;EoDpGA;IACE,wBAA+B;ErDyzUnC;AACF;;AC7sUI;EoD3GA;IACE,wBAA+B;ErD4zUnC;AACF;;AC9sUI;EoD7GA;IACE,wBAA+B;ErD+zUnC;AACF;;AC1sUI;EoDpHA;IACE,wBAA+B;ErDk0UnC;AACF;;AqD/1UE;EACE,0BAA+B;ArDk2UnC;;AClwUE;EoD9FE;IACE,0BAA+B;ErDo2UnC;AACF;;ACpwUE;EoD/FE;IACE,0BAA+B;ErDu2UnC;AACF;;ACtwUE;EoDhGE;IACE,0BAA+B;ErD02UnC;AACF;;ACxwUE;EoDjGE;IACE,0BAA+B;ErD62UnC;AACF;;AC1wUE;EoDlGE;IACE,0BAA+B;ErDg3UnC;AACF;;AC3wUI;EoDpGA;IACE,0BAA+B;ErDm3UnC;AACF;;ACvwUI;EoD3GA;IACE,0BAA+B;ErDs3UnC;AACF;;ACxwUI;EoD7GA;IACE,0BAA+B;ErDy3UnC;AACF;;ACpwUI;EoDpHA;IACE,0BAA+B;ErD43UnC;AACF;;AqDz5UE;EACE,gCAA+B;ArD45UnC;;AC5zUE;EoD9FE;IACE,gCAA+B;ErD85UnC;AACF;;AC9zUE;EoD/FE;IACE,gCAA+B;ErDi6UnC;AACF;;ACh0UE;EoDhGE;IACE,gCAA+B;ErDo6UnC;AACF;;ACl0UE;EoDjGE;IACE,gCAA+B;ErDu6UnC;AACF;;ACp0UE;EoDlGE;IACE,gCAA+B;ErD06UnC;AACF;;ACr0UI;EoDpGA;IACE,gCAA+B;ErD66UnC;AACF;;ACj0UI;EoD3GA;IACE,gCAA+B;ErDg7UnC;AACF;;ACl0UI;EoD7GA;IACE,gCAA+B;ErDm7UnC;AACF;;AC9zUI;EoDpHA;IACE,gCAA+B;ErDs7UnC;AACF;;AqDn9UE;EACE,+BAA+B;ArDs9UnC;;ACt3UE;EoD9FE;IACE,+BAA+B;ErDw9UnC;AACF;;ACx3UE;EoD/FE;IACE,+BAA+B;ErD29UnC;AACF;;AC13UE;EoDhGE;IACE,+BAA+B;ErD89UnC;AACF;;AC53UE;EoDjGE;IACE,+BAA+B;ErDi+UnC;AACF;;AC93UE;EoDlGE;IACE,+BAA+B;ErDo+UnC;AACF;;AC/3UI;EoDpGA;IACE,+BAA+B;ErDu+UnC;AACF;;AC33UI;EoD3GA;IACE,+BAA+B;ErD0+UnC;AACF;;AC53UI;EoD7GA;IACE,+BAA+B;ErD6+UnC;AACF;;ACx3UI;EoDpHA;IACE,+BAA+B;ErDg/UnC;AACF;;AqD/+UA;EACE,wBAAwB;ArDk/U1B;;AqDh/UA;EACE,uBAAuB;EACvB,iCAAiC;EACjC,yBAAyB;EACzB,2BAA2B;EAC3B,qBAAqB;EACrB,6BAA6B;EAC7B,8BAA8B;EAC9B,wBAAwB;ArDm/U1B;;AC37UE;EoDrDA;IACE,wBAAwB;ErDo/U1B;AACF;;AC77UE;EoDrDA;IACE,wBAAwB;ErDs/U1B;AACF;;AC/7UE;EoDrDA;IACE,wBAAwB;ErDw/U1B;AACF;;ACj8UE;EoDrDA;IACE,wBAAwB;ErD0/U1B;AACF;;ACn8UE;EoDrDA;IACE,wBAAwB;ErD4/U1B;AACF;;ACp8UI;EoDtDF;IACE,wBAAwB;ErD8/U1B;AACF;;ACh8UI;EoD5DF;IACE,wBAAwB;ErDggV1B;AACF;;ACj8UI;EoD7DF;IACE,wBAAwB;ErDkgV1B;AACF;;AC77UI;EoDnEF;IACE,wBAAwB;ErDogV1B;AACF;;AqDngVA;EACE,6BAA6B;ArDsgV/B;;ACr/UE;EoDdA;IACE,6BAA6B;ErDugV/B;AACF;;ACv/UE;EoDdA;IACE,6BAA6B;ErDygV/B;AACF;;ACz/UE;EoDdA;IACE,6BAA6B;ErD2gV/B;AACF;;AC3/UE;EoDdA;IACE,6BAA6B;ErD6gV/B;AACF;;AC7/UE;EoDdA;IACE,6BAA6B;ErD+gV/B;AACF;;AC9/UI;EoDfF;IACE,6BAA6B;ErDihV/B;AACF;;AC1/UI;EoDrBF;IACE,6BAA6B;ErDmhV/B;AACF;;AC3/UI;EoDtBF;IACE,6BAA6B;ErDqhV/B;AACF;;ACv/UI;EoD5BF;IACE,6BAA6B;ErDuhV/B;AACF;;AsDjpVA,iBAAA;ACWA;EACE,oBAAoB;EACpB,aAAa;EACb,sBAAsB;EACtB,8BAA8B;AvD0oVhC;;AuD9oVA;EAMI,gBAAgB;AvD4oVpB;;AuDlpVA;EASM,mBAAmB;AvD6oVzB;;AuDtpVA;EAeM,uBxDXyB;EwDYzB,cxDzBuB;ACoqV7B;;AuD3pVA;;EAmBQ,cAAc;AvD6oVtB;;AuDhqVA;EAqBQ,cxD9BqB;AC6qV7B;;AuDpqVA;EAuBQ,4BxDhCqB;ACirV7B;;AuDxqVA;;EA0BU,cxDnCmB;ACsrV7B;;ACtkVE;EsDvGF;IA6BU,uBxDzBqB;EC8qV7B;AACF;;AuDnrVA;;EAgCQ,4BxDzCqB;ACisV7B;;AuDxrVA;;;EAqCU,yB7C4DuB;E6C3DvB,cxD/CmB;ACwsV7B;;AuD/rVA;EAyCU,cxDlDmB;EwDmDnB,YAAY;AvD0pVtB;;AuDpsVA;EA4CY,UAAU;AvD4pVtB;;AuDxsVA;EA+CY,uBAAwB;EACxB,UAAU;AvD6pVtB;;AuD7sVA;EAoDY,cxD7DiB;AC0tV7B;;AuDjtVA;EAsDc,uCxD/De;AC8tV7B;;AuDrtVA;EA0Dc,yBxDnEe;EwDoEf,qBxDpEe;EwDqEf,YxDxDiB;ACutV/B;;AuD3tVA;EAkEU,4EAAyG;AvD6pVnH;;ACpoVE;EsD3FF;IAqEc,4EAAyG;EvD+pVrH;AACF;;AuDruVA;EAeM,yBxDxBuB;EwDyBvB,YxDZyB;ACsuV/B;;AuD1uVA;;EAmBQ,cAAc;AvD4tVtB;;AuD/uVA;EAqBQ,YxDjBuB;AC+uV/B;;AuDnvVA;EAuBQ,+BxDnBuB;ACmvV/B;;AuDvvVA;;EA0BU,YxDtBqB;ACwvV/B;;ACrpVE;EsDvGF;IA6BU,yBxDtCmB;EC0wV3B;AACF;;AuDlwVA;;EAgCQ,+BxD5BuB;ACmwV/B;;AuDvwVA;;;EAqCU,uB7C4DuB;E6C3DvB,YxDlCqB;AC0wV/B;;AuD9wVA;EAyCU,YxDrCqB;EwDsCrB,YAAY;AvDyuVtB;;AuDnxVA;EA4CY,UAAU;AvD2uVtB;;AuDvxVA;EA+CY,yBAAwB;EACxB,UAAU;AvD4uVtB;;AuD5xVA;EAoDY,YxDhDmB;AC4xV/B;;AuDhyVA;EAsDc,uCxD/De;AC6yV7B;;AuDpyVA;EA0Dc,uBxDtDiB;EwDuDjB,mBxDvDiB;EwDwDjB,cxDrEe;ACmzV7B;;AuD1yVA;EAkEU,8EAAyG;AvD4uVnH;;ACntVE;EsD3FF;IAqEc,8EAAyG;EvD8uVrH;AACF;;AuDpzVA;EAeM,4BxDbwB;EwDcxB,yB7CqDe;AVovVrB;;AuDzzVA;;EAmBQ,cAAc;AvD2yVtB;;AuD9zVA;EAqBQ,yB7CgDa;AV6vVrB;;AuDl0VA;EAuBQ,yB7C8Ca;AViwVrB;;AuDt0VA;;EA0BU,yB7C2CW;AVswVrB;;ACpuVE;EsDvGF;IA6BU,4BxD3BoB;EC80V5B;AACF;;AuDj1VA;;EAgCQ,yB7CqCa;AVixVrB;;AuDt1VA;;;EAqCU,yB7C4DuB;E6C3DvB,yB7C+BW;AVwxVrB;;AuD71VA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDwzVtB;;AuDl2VA;EA4CY,UAAU;AvD0zVtB;;AuDt2VA;EA+CY,4BAAwB;EACxB,UAAU;AvD2zVtB;;AuD32VA;EAoDY,yB7CiBS;AV0yVrB;;AuD/2VA;EAsDc,uCxD/De;AC43V7B;;AuDn3VA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,iBxD1DgB;ACu3V9B;;AuDz3VA;EAkEU,iFAAyG;AvD2zVnH;;AClyVE;EsD3FF;IAqEc,iFAAyG;EvD6zVrH;AACF;;AuDn4VA;EAeM,yBxDpBwB;EwDqBxB,W7CuDU;AVi0VhB;;AuDx4VA;;EAmBQ,cAAc;AvD03VtB;;AuD74VA;EAqBQ,W7CkDQ;AV00VhB;;AuDj5VA;EAuBQ,+B7CgDQ;AV80VhB;;AuDr5VA;;EA0BU,W7C6CM;AVm1VhB;;ACnzVE;EsDvGF;IA6BU,yBxDlCoB;ECo6V5B;AACF;;AuDh6VA;;EAgCQ,+B7CuCQ;AV81VhB;;AuDr6VA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVq2VhB;;AuD56VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDu4VtB;;AuDj7VA;EA4CY,UAAU;AvDy4VtB;;AuDr7VA;EA+CY,yBAAwB;EACxB,UAAU;AvD04VtB;;AuD17VA;EAoDY,W7CmBI;AVu3VhB;;AuD97VA;EAsDc,uCxD/De;AC28V7B;;AuDl8VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjEgB;AC68V9B;;AuDx8VA;EAkEU,gFAAyG;AvD04VnH;;ACj3VE;EsD3FF;IAqEc,gFAAyG;EvD44VrH;AACF;;AuDl9VA;EAeM,yBxDN4B;EwDO5B,W7CuDU;AVg5VhB;;AuDv9VA;;EAmBQ,cAAc;AvDy8VtB;;AuD59VA;EAqBQ,W7CkDQ;AVy5VhB;;AuDh+VA;EAuBQ,+B7CgDQ;AV65VhB;;AuDp+VA;;EA0BU,W7C6CM;AVk6VhB;;ACl4VE;EsDvGF;IA6BU,yBxDpBwB;ECq+VhC;AACF;;AuD/+VA;;EAgCQ,+B7CuCQ;AV66VhB;;AuDp/VA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVo7VhB;;AuD3/VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDs9VtB;;AuDhgWA;EA4CY,UAAU;AvDw9VtB;;AuDpgWA;EA+CY,yBAAwB;EACxB,UAAU;AvDy9VtB;;AuDzgWA;EAoDY,W7CmBI;AVs8VhB;;AuD7gWA;EAsDc,uCxD/De;AC0hW7B;;AuDjhWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDnDoB;AC8gWlC;;AuDvhWA;EAkEU,gFAAyG;AvDy9VnH;;ACh8VE;EsD3FF;IAqEc,gFAAyG;EvD29VrH;AACF;;AuDjiWA;EAeM,yBxDJ4B;EwDK5B,W7CuDU;AV+9VhB;;AuDtiWA;;EAmBQ,cAAc;AvDwhWtB;;AuD3iWA;EAqBQ,W7CkDQ;AVw+VhB;;AuD/iWA;EAuBQ,+B7CgDQ;AV4+VhB;;AuDnjWA;;EA0BU,W7C6CM;AVi/VhB;;ACj9VE;EsDvGF;IA6BU,yBxDlBwB;ECkjWhC;AACF;;AuD9jWA;;EAgCQ,+B7CuCQ;AV4/VhB;;AuDnkWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVmgWhB;;AuD1kWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDqiWtB;;AuD/kWA;EA4CY,UAAU;AvDuiWtB;;AuDnlWA;EA+CY,yBAAwB;EACxB,UAAU;AvDwiWtB;;AuDxlWA;EAoDY,W7CmBI;AVqhWhB;;AuD5lWA;EAsDc,uCxD/De;ACymW7B;;AuDhmWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjDoB;AC2lWlC;;AuDtmWA;EAkEU,gFAAyG;AvDwiWnH;;AC/gWE;EsD3FF;IAqEc,gFAAyG;EvD0iWrH;AACF;;AuDhnWA;EAeM,yBxDL4B;EwDM5B,W7CuDU;AV8iWhB;;AuDrnWA;;EAmBQ,cAAc;AvDumWtB;;AuD1nWA;EAqBQ,W7CkDQ;AVujWhB;;AuD9nWA;EAuBQ,+B7CgDQ;AV2jWhB;;AuDloWA;;EA0BU,W7C6CM;AVgkWhB;;AChiWE;EsDvGF;IA6BU,yBxDnBwB;ECkoWhC;AACF;;AuD7oWA;;EAgCQ,+B7CuCQ;AV2kWhB;;AuDlpWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVklWhB;;AuDzpWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDonWtB;;AuD9pWA;EA4CY,UAAU;AvDsnWtB;;AuDlqWA;EA+CY,yBAAwB;EACxB,UAAU;AvDunWtB;;AuDvqWA;EAoDY,W7CmBI;AVomWhB;;AuD3qWA;EAsDc,uCxD/De;ACwrW7B;;AuD/qWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDlDoB;AC2qWlC;;AuDrrWA;EAkEU,gFAAyG;AvDunWnH;;AC9lWE;EsD3FF;IAqEc,gFAAyG;EvDynWrH;AACF;;AuD/rWA;EAeM,yBxDP4B;EwDQ5B,W7CuDU;AV6nWhB;;AuDpsWA;;EAmBQ,cAAc;AvDsrWtB;;AuDzsWA;EAqBQ,W7CkDQ;AVsoWhB;;AuD7sWA;EAuBQ,+B7CgDQ;AV0oWhB;;AuDjtWA;;EA0BU,W7C6CM;AV+oWhB;;AC/mWE;EsDvGF;IA6BU,yBxDrBwB;ECmtWhC;AACF;;AuD5tWA;;EAgCQ,+B7CuCQ;AV0pWhB;;AuDjuWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AViqWhB;;AuDxuWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDmsWtB;;AuD7uWA;EA4CY,UAAU;AvDqsWtB;;AuDjvWA;EA+CY,yBAAwB;EACxB,UAAU;AvDssWtB;;AuDtvWA;EAoDY,W7CmBI;AVmrWhB;;AuD1vWA;EAsDc,uCxD/De;ACuwW7B;;AuD9vWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDpDoB;AC4vWlC;;AuDpwWA;EAkEU,gFAAyG;AvDssWnH;;AC7qWE;EsD3FF;IAqEc,gFAAyG;EvDwsWrH;AACF;;AuD9wWA;EAeM,yBxDR4B;EwDS5B,yB7CqDe;AV8sWrB;;AuDnxWA;;EAmBQ,cAAc;AvDqwWtB;;AuDxxWA;EAqBQ,yB7CgDa;AVutWrB;;AuD5xWA;EAuBQ,yB7C8Ca;AV2tWrB;;AuDhyWA;;EA0BU,yB7C2CW;AVguWrB;;AC9rWE;EsDvGF;IA6BU,yBxDtBwB;ECmyWhC;AACF;;AuD3yWA;;EAgCQ,yB7CqCa;AV2uWrB;;AuDhzWA;;;EAqCU,yB7C4DuB;E6C3DvB,yB7C+BW;AVkvWrB;;AuDvzWA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDkxWtB;;AuD5zWA;EA4CY,UAAU;AvDoxWtB;;AuDh0WA;EA+CY,yBAAwB;EACxB,UAAU;AvDqxWtB;;AuDr0WA;EAoDY,yB7CiBS;AVowWrB;;AuDz0WA;EAsDc,uCxD/De;ACs1W7B;;AuD70WA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,cxDrDoB;AC40WlC;;AuDn1WA;EAkEU,gFAAyG;AvDqxWnH;;AC5vWE;EsD3FF;IAqEc,gFAAyG;EvDuxWrH;AACF;;AuD71WA;EAeM,yBxDF2B;EwDG3B,W7CuDU;AV2xWhB;;AuDl2WA;;EAmBQ,cAAc;AvDo1WtB;;AuDv2WA;EAqBQ,W7CkDQ;AVoyWhB;;AuD32WA;EAuBQ,+B7CgDQ;AVwyWhB;;AuD/2WA;;EA0BU,W7C6CM;AV6yWhB;;AC7wWE;EsDvGF;IA6BU,yBxDhBuB;EC42W/B;AACF;;AuD13WA;;EAgCQ,+B7CuCQ;AVwzWhB;;AuD/3WA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AV+zWhB;;AuDt4WA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDi2WtB;;AuD34WA;EA4CY,UAAU;AvDm2WtB;;AuD/4WA;EA+CY,yBAAwB;EACxB,UAAU;AvDo2WtB;;AuDp5WA;EAoDY,W7CmBI;AVi1WhB;;AuDx5WA;EAsDc,uCxD/De;ACq6W7B;;AuD55WA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxD/CmB;ACq5WjC;;AuDl6WA;EAkEU,gFAAyG;AvDo2WnH;;AC30WE;EsD3FF;IAqEc,gFAAyG;EvDs2WrH;AACF;;AuD56WA;EAyEM,eAhF0B;AvDu7WhC;;ACj1WE;EsD/FF;IA6EQ,oBAnF8B;EvD27WpC;AACF;;ACv1WE;EsD/FF;IAiFQ,mBAtF4B;EvDg8WlC;AACF;;AuD57WA;EAsFM,mBAAmB;EACnB,aAAa;AvD02WnB;;AuDj8WA;EAyFQ,YAAY;EACZ,cAAc;AvD42WtB;;AuDt8WA;EA4FI,gBAAgB;AvD82WpB;;AuD18WA;EA8FI,iBAAiB;AvDg3WrB;;AuD52WA;EAEE,gBAAgB;AvD82WlB;;AuDh3WA;EAII,SAAS;EACT,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,QAAQ;EACR,qCAAqC;AvDg3WzC;;AuDz3WA;EAYI,YAAY;AvDi3WhB;;ACp4WE;EsDOF;IAeI,aAAa;EvDm3Wf;AACF;;AuDl3WA;EACE,kBAAkB;AvDq3WpB;;AC94WE;EsDwBF;IAKM,aAAa;EvDs3WjB;EuD33WF;IAOQ,sBAAsB;EvDu3W5B;AACF;;ACn5WE;EsDoBF;IASI,aAAa;IACb,uBAAuB;EvD23WzB;EuDr4WF;ItDsDI,oBsD1CwC;EvD43W1C;AACF;;AuDz3WA;;EAEE,YAAY;EACZ,cAAc;AvD43WhB;;AuD13WA;EACE,YAAY;EACZ,cAAc;EACd,oBApJ6B;AvDihX/B;;ACz6WE;EsDyCF;IAKI,kBArJgC;EvDqhXlC;AACF;;AwDlhXA;EACE,oBAN2B;AxD2hX7B;;ACv6WE;EuD/GF;IAII,kBAR+B;ExD+hXjC;EwD3hXF;IAOM,oBAV8B;ExDiiXlC;EwD9hXF;IASM,mBAX4B;ExDmiXhC;AACF;;AyDniXA;EACE,yB1DO4B;E0DN5B,yBAJ+B;AzD0iXjC","file":"bulma.css"} \ No newline at end of file diff --git a/templ/examples/counter-basic/assets/bulma.min.css b/templ/examples/counter-basic/assets/bulma.min.css new file mode 100644 index 0000000..86ad2ff --- /dev/null +++ b/templ/examples/counter-basic/assets/bulma.min.css @@ -0,0 +1 @@ +/*! bulma.io v0.9.4 | MIT License | github.com/jgthms/bulma */.button,.file-cta,.file-name,.input,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.select select,.textarea{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(.5em - 1px);padding-left:calc(.75em - 1px);padding-right:calc(.75em - 1px);padding-top:calc(.5em - 1px);position:relative;vertical-align:top}.button:active,.button:focus,.file-cta:active,.file-cta:focus,.file-name:active,.file-name:focus,.input:active,.input:focus,.is-active.button,.is-active.file-cta,.is-active.file-name,.is-active.input,.is-active.pagination-ellipsis,.is-active.pagination-link,.is-active.pagination-next,.is-active.pagination-previous,.is-active.textarea,.is-focused.button,.is-focused.file-cta,.is-focused.file-name,.is-focused.input,.is-focused.pagination-ellipsis,.is-focused.pagination-link,.is-focused.pagination-next,.is-focused.pagination-previous,.is-focused.textarea,.pagination-ellipsis:active,.pagination-ellipsis:focus,.pagination-link:active,.pagination-link:focus,.pagination-next:active,.pagination-next:focus,.pagination-previous:active,.pagination-previous:focus,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{outline:0}.button[disabled],.file-cta[disabled],.file-name[disabled],.input[disabled],.pagination-ellipsis[disabled],.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .button,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .input,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-previous,fieldset[disabled] .select select,fieldset[disabled] .textarea{cursor:not-allowed}.breadcrumb,.button,.file,.is-unselectable,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.tabs{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid transparent;border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:.625em;margin-top:-.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:.625em}.block:not(:last-child),.box:not(:last-child),.breadcrumb:not(:last-child),.content:not(:last-child),.level:not(:last-child),.message:not(:last-child),.notification:not(:last-child),.pagination:not(:last-child),.progress:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.tabs:not(:last-child),.title:not(:last-child){margin-bottom:1.5rem}.delete,.modal-close{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:0;position:relative;vertical-align:top;width:20px}.delete::after,.delete::before,.modal-close::after,.modal-close::before{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.delete::before,.modal-close::before{height:2px;width:50%}.delete::after,.modal-close::after{height:50%;width:2px}.delete:focus,.delete:hover,.modal-close:focus,.modal-close:hover{background-color:rgba(10,10,10,.3)}.delete:active,.modal-close:active{background-color:rgba(10,10,10,.4)}.is-small.delete,.is-small.modal-close{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.delete,.is-medium.modal-close{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.delete,.is-large.modal-close{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.button.is-loading::after,.control.is-loading::after,.loader,.select.is-loading::after{-webkit-animation:spinAround .5s infinite linear;animation:spinAround .5s infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img,.is-overlay,.modal,.modal-background{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:scroll;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#4a4a4a;font-size:1em;font-weight:400;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:#f5f5f5;color:#da1039;font-size:.875em;font-weight:400;padding:.25em .5em .25em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type=checkbox],input[type=radio]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#363636;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#4a4a4a;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#363636}@-webkit-keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}@keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;display:block;padding:1.25rem}a.box:focus,a.box:hover{box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px #485fc7}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2),0 0 0 1px #485fc7}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-large,.button .icon.is-medium,.button .icon.is-small{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-.5em - 1px);margin-right:calc(-.5em - 1px)}.button.is-hovered,.button:hover{border-color:#b5b5b5;color:#363636}.button.is-focused,.button:focus{border-color:#485fc7;color:#363636}.button.is-focused:not(:active),.button:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-active,.button:active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#4a4a4a;text-decoration:underline}.button.is-text.is-focused,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text:hover{background-color:#f5f5f5;color:#363636}.button.is-text.is-active,.button.is-text:active{background-color:#e8e8e8;color:#363636}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:0 0;border-color:transparent;color:#485fc7;text-decoration:none}.button.is-ghost.is-hovered,.button.is-ghost:hover{color:#485fc7;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white.is-hovered,.button.is-white:hover{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white.is-focused,.button.is-white:focus{border-color:transparent;color:#0a0a0a}.button.is-white.is-focused:not(:active),.button.is-white:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.button.is-white.is-active,.button.is-white:active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-hovered,.button.is-white.is-inverted:hover{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined.is-focused,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-outlined.is-loading.is-focused::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined.is-focused,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined:hover{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black.is-hovered,.button.is-black:hover{background-color:#040404;border-color:transparent;color:#fff}.button.is-black.is-focused,.button.is-black:focus{border-color:transparent;color:#fff}.button.is-black.is-focused:not(:active),.button.is-black:focus:not(:active){box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.button.is-black.is-active,.button.is-black:active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-hovered,.button.is-black.is-inverted:hover{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined.is-focused,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-outlined.is-loading.is-focused::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined.is-focused,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined:hover{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-hovered,.button.is-light:hover{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused,.button.is-light:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused:not(:active),.button.is-light:focus:not(:active){box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.button.is-light.is-active,.button.is-light:active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-hovered,.button.is-light.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined.is-focused,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-outlined.is-loading.is-focused::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-light.is-inverted.is-outlined.is-focused,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-dark{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark.is-hovered,.button.is-dark:hover{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark.is-focused,.button.is-dark:focus{border-color:transparent;color:#fff}.button.is-dark.is-focused:not(:active),.button.is-dark:focus:not(:active){box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.button.is-dark.is-active,.button.is-dark:active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],fieldset[disabled] .button.is-dark{background-color:#363636;border-color:#363636;box-shadow:none}.button.is-dark.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-hovered,.button.is-dark.is-inverted:hover{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined.is-focused,.button.is-dark.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.button.is-dark.is-outlined:hover{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-outlined.is-loading.is-focused::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined.is-focused,.button.is-dark.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined:hover{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary{background-color:#00d1b2;border-color:transparent;color:#fff}.button.is-primary.is-hovered,.button.is-primary:hover{background-color:#00c4a7;border-color:transparent;color:#fff}.button.is-primary.is-focused,.button.is-primary:focus{border-color:transparent;color:#fff}.button.is-primary.is-focused:not(:active),.button.is-primary:focus:not(:active){box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.button.is-primary.is-active,.button.is-primary:active{background-color:#00b89c;border-color:transparent;color:#fff}.button.is-primary[disabled],fieldset[disabled] .button.is-primary{background-color:#00d1b2;border-color:#00d1b2;box-shadow:none}.button.is-primary.is-inverted{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-hovered,.button.is-primary.is-inverted:hover{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],fieldset[disabled] .button.is-primary.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#00d1b2}.button.is-primary.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;color:#00d1b2}.button.is-primary.is-outlined.is-focused,.button.is-primary.is-outlined.is-hovered,.button.is-primary.is-outlined:focus,.button.is-primary.is-outlined:hover{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.button.is-primary.is-outlined.is-loading::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-outlined.is-loading.is-focused::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-outlined.is-loading:focus::after,.button.is-primary.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;box-shadow:none;color:#00d1b2}.button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined.is-focused,.button.is-primary.is-inverted.is-outlined.is-hovered,.button.is-primary.is-inverted.is-outlined:focus,.button.is-primary.is-inverted.is-outlined:hover{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light{background-color:#ebfffc;color:#00947e}.button.is-primary.is-light.is-hovered,.button.is-primary.is-light:hover{background-color:#defffa;border-color:transparent;color:#00947e}.button.is-primary.is-light.is-active,.button.is-primary.is-light:active{background-color:#d1fff8;border-color:transparent;color:#00947e}.button.is-link{background-color:#485fc7;border-color:transparent;color:#fff}.button.is-link.is-hovered,.button.is-link:hover{background-color:#3e56c4;border-color:transparent;color:#fff}.button.is-link.is-focused,.button.is-link:focus{border-color:transparent;color:#fff}.button.is-link.is-focused:not(:active),.button.is-link:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-link.is-active,.button.is-link:active{background-color:#3a51bb;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#485fc7;border-color:#485fc7;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-hovered,.button.is-link.is-inverted:hover{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#485fc7}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;color:#485fc7}.button.is-link.is-outlined.is-focused,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined:hover{background-color:#485fc7;border-color:#485fc7;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-outlined.is-loading.is-focused::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;box-shadow:none;color:#485fc7}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined.is-focused,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined:hover{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff1fa;color:#3850b7}.button.is-link.is-light.is-hovered,.button.is-link.is-light:hover{background-color:#e6e9f7;border-color:transparent;color:#3850b7}.button.is-link.is-light.is-active,.button.is-link.is-light:active{background-color:#dce0f4;border-color:transparent;color:#3850b7}.button.is-info{background-color:#3e8ed0;border-color:transparent;color:#fff}.button.is-info.is-hovered,.button.is-info:hover{background-color:#3488ce;border-color:transparent;color:#fff}.button.is-info.is-focused,.button.is-info:focus{border-color:transparent;color:#fff}.button.is-info.is-focused:not(:active),.button.is-info:focus:not(:active){box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.button.is-info.is-active,.button.is-info:active{background-color:#3082c5;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#3e8ed0;border-color:#3e8ed0;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-hovered,.button.is-info.is-inverted:hover{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#3e8ed0}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;color:#3e8ed0}.button.is-info.is-outlined.is-focused,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined:hover{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-outlined.is-loading.is-focused::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;box-shadow:none;color:#3e8ed0}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined.is-focused,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined:hover{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#eff5fb;color:#296fa8}.button.is-info.is-light.is-hovered,.button.is-info.is-light:hover{background-color:#e4eff9;border-color:transparent;color:#296fa8}.button.is-info.is-light.is-active,.button.is-info.is-light:active{background-color:#dae9f6;border-color:transparent;color:#296fa8}.button.is-success{background-color:#48c78e;border-color:transparent;color:#fff}.button.is-success.is-hovered,.button.is-success:hover{background-color:#3ec487;border-color:transparent;color:#fff}.button.is-success.is-focused,.button.is-success:focus{border-color:transparent;color:#fff}.button.is-success.is-focused:not(:active),.button.is-success:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.button.is-success.is-active,.button.is-success:active{background-color:#3abb81;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#48c78e;border-color:#48c78e;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-hovered,.button.is-success.is-inverted:hover{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#48c78e}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;color:#48c78e}.button.is-success.is-outlined.is-focused,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined:hover{background-color:#48c78e;border-color:#48c78e;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-outlined.is-loading.is-focused::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;box-shadow:none;color:#48c78e}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined.is-focused,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined:hover{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#effaf5;color:#257953}.button.is-success.is-light.is-hovered,.button.is-success.is-light:hover{background-color:#e6f7ef;border-color:transparent;color:#257953}.button.is-success.is-light.is-active,.button.is-success.is-light:active{background-color:#dcf4e9;border-color:transparent;color:#257953}.button.is-warning{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-hovered,.button.is-warning:hover{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused,.button.is-warning:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused:not(:active),.button.is-warning:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.button.is-warning.is-active,.button.is-warning:active{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffe08a;border-color:#ffe08a;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-hovered,.button.is-warning.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#ffe08a}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;color:#ffe08a}.button.is-warning.is-outlined.is-focused,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined:hover{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-outlined.is-loading.is-focused::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;box-shadow:none;color:#ffe08a}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-warning.is-inverted.is-outlined.is-focused,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-warning.is-light{background-color:#fffaeb;color:#946c00}.button.is-warning.is-light.is-hovered,.button.is-warning.is-light:hover{background-color:#fff6de;border-color:transparent;color:#946c00}.button.is-warning.is-light.is-active,.button.is-warning.is-light:active{background-color:#fff3d1;border-color:transparent;color:#946c00}.button.is-danger{background-color:#f14668;border-color:transparent;color:#fff}.button.is-danger.is-hovered,.button.is-danger:hover{background-color:#f03a5f;border-color:transparent;color:#fff}.button.is-danger.is-focused,.button.is-danger:focus{border-color:transparent;color:#fff}.button.is-danger.is-focused:not(:active),.button.is-danger:focus:not(:active){box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.button.is-danger.is-active,.button.is-danger:active{background-color:#ef2e55;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#f14668;border-color:#f14668;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-hovered,.button.is-danger.is-inverted:hover{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#f14668}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;color:#f14668}.button.is-danger.is-outlined.is-focused,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined:hover{background-color:#f14668;border-color:#f14668;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-outlined.is-loading.is-focused::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;box-shadow:none;color:#f14668}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined.is-focused,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined:hover{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.button.is-danger.is-light.is-hovered,.button.is-danger.is-light:hover{background-color:#fde0e6;border-color:transparent;color:#cc0f35}.button.is-danger.is-light.is-active,.button.is-danger.is-light:active{background-color:#fcd4dc;border-color:transparent;color:#cc0f35}.button.is-small{font-size:.75rem}.button.is-small:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent!important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * .5));top:calc(50% - (1em * .5));position:absolute!important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#7a7a7a;box-shadow:none;pointer-events:none}.button.is-rounded{border-radius:9999px;padding-left:calc(1em + .25em);padding-right:calc(1em + .25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}.buttons:last-child{margin-bottom:-.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button.is-hovered,.buttons.has-addons .button:hover{z-index:2}.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-focused,.buttons.has-addons .button.is-selected,.buttons.has-addons .button:active,.buttons.has-addons .button:focus{z-index:3}.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button.is-selected:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button:focus:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}@media screen and (max-width:768px){.button.is-responsive.is-small{font-size:.5625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.65625rem}.button.is-responsive.is-medium{font-size:.75rem}.button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.button.is-responsive.is-small{font-size:.65625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.75rem}.button.is-responsive.is-medium{font-size:1rem}.button.is-responsive.is-large{font-size:1.25rem}}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none!important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width:1024px){.container{max-width:960px}}@media screen and (max-width:1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width:1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width:1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width:1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:.25em}.content blockquote:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content p:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child),.content ul:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#363636;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:.8em}.content h5{font-size:1.125em;margin-bottom:.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sub,.content sup{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.content table th{color:#363636}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#363636}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#363636}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:9999px}.image.is-fullwidth{width:100%}.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img{height:100%;width:100%}.image.is-1by1,.image.is-square{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:0 0}.notification>.delete{right:.5rem;position:absolute;top:.5rem}.notification .content,.notification .subtitle,.notification .title{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.notification.is-dark{background-color:#363636;color:#fff}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-primary.is-light{background-color:#ebfffc;color:#00947e}.notification.is-link{background-color:#485fc7;color:#fff}.notification.is-link.is-light{background-color:#eff1fa;color:#3850b7}.notification.is-info{background-color:#3e8ed0;color:#fff}.notification.is-info.is-light{background-color:#eff5fb;color:#296fa8}.notification.is-success{background-color:#48c78e;color:#fff}.notification.is-success.is-light{background-color:#effaf5;color:#257953}.notification.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.notification.is-warning.is-light{background-color:#fffaeb;color:#946c00}.notification.is-danger{background-color:#f14668;color:#fff}.notification.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right,#fff 30%,#ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right,#0a0a0a 30%,#ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right,#f5f5f5 30%,#ededed 30%)}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate{background-image:linear-gradient(to right,#363636 30%,#ededed 30%)}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-primary:indeterminate{background-image:linear-gradient(to right,#00d1b2 30%,#ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#485fc7}.progress.is-link::-moz-progress-bar{background-color:#485fc7}.progress.is-link::-ms-fill{background-color:#485fc7}.progress.is-link:indeterminate{background-image:linear-gradient(to right,#485fc7 30%,#ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#3e8ed0}.progress.is-info::-moz-progress-bar{background-color:#3e8ed0}.progress.is-info::-ms-fill{background-color:#3e8ed0}.progress.is-info:indeterminate{background-image:linear-gradient(to right,#3e8ed0 30%,#ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#48c78e}.progress.is-success::-moz-progress-bar{background-color:#48c78e}.progress.is-success::-ms-fill{background-color:#48c78e}.progress.is-success:indeterminate{background-image:linear-gradient(to right,#48c78e 30%,#ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffe08a}.progress.is-warning::-moz-progress-bar{background-color:#ffe08a}.progress.is-warning::-ms-fill{background-color:#ffe08a}.progress.is-warning:indeterminate{background-image:linear-gradient(to right,#ffe08a 30%,#ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#f14668}.progress.is-danger::-moz-progress-bar{background-color:#f14668}.progress.is-danger::-ms-fill{background-color:#f14668}.progress.is-danger:indeterminate{background-image:linear-gradient(to right,#f14668 30%,#ededed 30%)}.progress:indeterminate{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:moveIndeterminate;animation-name:moveIndeterminate;-webkit-animation-timing-function:linear;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right,#4a4a4a 30%,#ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@-webkit-keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#485fc7;border-color:#485fc7;color:#fff}.table td.is-info,.table th.is-info{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.table td.is-success,.table th.is-success{background-color:#48c78e;border-color:#48c78e;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.table td.is-danger,.table th.is-danger{background-color:#f14668;border-color:#f14668;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#363636}.table th:not([align]){text-align:left}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:transparent}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot{background-color:transparent}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody{background-color:transparent}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(2n){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:.25em .5em}.table.is-striped tbody tr:not(.is-selected):nth-child(2n){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:.5rem}.tags .tag:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:.25rem;margin-left:.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.tags.has-addons .tag:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:.75em;padding-right:.75em;white-space:nowrap}.tag:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.tag:not(body).is-dark{background-color:#363636;color:#fff}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-primary.is-light{background-color:#ebfffc;color:#00947e}.tag:not(body).is-link{background-color:#485fc7;color:#fff}.tag:not(body).is-link.is-light{background-color:#eff1fa;color:#3850b7}.tag:not(body).is-info{background-color:#3e8ed0;color:#fff}.tag:not(body).is-info.is-light{background-color:#eff5fb;color:#296fa8}.tag:not(body).is-success{background-color:#48c78e;color:#fff}.tag:not(body).is-success.is-light{background-color:#effaf5;color:#257953}.tag:not(body).is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.tag:not(body).is-warning.is-light{background-color:#fffaeb;color:#946c00}.tag:not(body).is-danger{background-color:#f14668;color:#fff}.tag:not(body).is-danger.is-light{background-color:#feecf0;color:#cc0f35}.tag:not(body).is-normal{font-size:.75rem}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag:not(body).is-delete{margin-left:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::after,.tag:not(body).is-delete::before{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:focus,.tag:not(body).is-delete:hover{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:9999px}a.tag:hover{text-decoration:underline}.subtitle,.title{word-break:break-word}.subtitle em,.subtitle span,.title em,.title span{font-weight:inherit}.subtitle sub,.title sub{font-size:.75em}.subtitle sup,.title sup{font-size:.75em}.subtitle .tag,.title .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:.25rem .5rem;text-align:center;vertical-align:top}.input,.select select,.textarea{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#363636}.input::-moz-placeholder,.select select::-moz-placeholder,.textarea::-moz-placeholder{color:rgba(54,54,54,.3)}.input::-webkit-input-placeholder,.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.input:-moz-placeholder,.select select:-moz-placeholder,.textarea:-moz-placeholder{color:rgba(54,54,54,.3)}.input:-ms-input-placeholder,.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:rgba(54,54,54,.3)}.input:hover,.is-hovered.input,.is-hovered.textarea,.select select.is-hovered,.select select:hover,.textarea:hover{border-color:#b5b5b5}.input:active,.input:focus,.is-active.input,.is-active.textarea,.is-focused.input,.is-focused.textarea,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{border-color:#485fc7;box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.input[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .input,fieldset[disabled] .select select,fieldset[disabled] .textarea{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.input[disabled]::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder{color:rgba(122,122,122,.3)}.input,.textarea{box-shadow:inset 0 .0625em .125em rgba(10,10,10,.05);max-width:100%;width:100%}.input[readonly],.textarea[readonly]{box-shadow:none}.is-white.input,.is-white.textarea{border-color:#fff}.is-white.input:active,.is-white.input:focus,.is-white.is-active.input,.is-white.is-active.textarea,.is-white.is-focused.input,.is-white.is-focused.textarea,.is-white.textarea:active,.is-white.textarea:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.is-black.input,.is-black.textarea{border-color:#0a0a0a}.is-black.input:active,.is-black.input:focus,.is-black.is-active.input,.is-black.is-active.textarea,.is-black.is-focused.input,.is-black.is-focused.textarea,.is-black.textarea:active,.is-black.textarea:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.is-light.input,.is-light.textarea{border-color:#f5f5f5}.is-light.input:active,.is-light.input:focus,.is-light.is-active.input,.is-light.is-active.textarea,.is-light.is-focused.input,.is-light.is-focused.textarea,.is-light.textarea:active,.is-light.textarea:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.is-dark.input,.is-dark.textarea{border-color:#363636}.is-dark.input:active,.is-dark.input:focus,.is-dark.is-active.input,.is-dark.is-active.textarea,.is-dark.is-focused.input,.is-dark.is-focused.textarea,.is-dark.textarea:active,.is-dark.textarea:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.is-primary.input,.is-primary.textarea{border-color:#00d1b2}.is-primary.input:active,.is-primary.input:focus,.is-primary.is-active.input,.is-primary.is-active.textarea,.is-primary.is-focused.input,.is-primary.is-focused.textarea,.is-primary.textarea:active,.is-primary.textarea:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.is-link.input,.is-link.textarea{border-color:#485fc7}.is-link.input:active,.is-link.input:focus,.is-link.is-active.input,.is-link.is-active.textarea,.is-link.is-focused.input,.is-link.is-focused.textarea,.is-link.textarea:active,.is-link.textarea:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.is-info.input,.is-info.textarea{border-color:#3e8ed0}.is-info.input:active,.is-info.input:focus,.is-info.is-active.input,.is-info.is-active.textarea,.is-info.is-focused.input,.is-info.is-focused.textarea,.is-info.textarea:active,.is-info.textarea:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.is-success.input,.is-success.textarea{border-color:#48c78e}.is-success.input:active,.is-success.input:focus,.is-success.is-active.input,.is-success.is-active.textarea,.is-success.is-focused.input,.is-success.is-focused.textarea,.is-success.textarea:active,.is-success.textarea:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.is-warning.input,.is-warning.textarea{border-color:#ffe08a}.is-warning.input:active,.is-warning.input:focus,.is-warning.is-active.input,.is-warning.is-active.textarea,.is-warning.is-focused.input,.is-warning.is-focused.textarea,.is-warning.textarea:active,.is-warning.textarea:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.is-danger.input,.is-danger.textarea{border-color:#f14668}.is-danger.input:active,.is-danger.input:focus,.is-danger.is-active.input,.is-danger.is-active.textarea,.is-danger.is-focused.input,.is-danger.is-focused.textarea,.is-danger.textarea:active,.is-danger.textarea:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.is-small.input,.is-small.textarea{border-radius:2px;font-size:.75rem}.is-medium.input,.is-medium.textarea{font-size:1.25rem}.is-large.input,.is-large.textarea{font-size:1.5rem}.is-fullwidth.input,.is-fullwidth.textarea{display:block;width:100%}.is-inline.input,.is-inline.textarea{display:inline;width:auto}.input.is-rounded{border-radius:9999px;padding-left:calc(calc(.75em - 1px) + .375em);padding-right:calc(calc(.75em - 1px) + .375em)}.input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.checkbox,.radio{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.checkbox input,.radio input{cursor:pointer}.checkbox:hover,.radio:hover{color:#363636}.checkbox input[disabled],.checkbox[disabled],.radio input[disabled],.radio[disabled],fieldset[disabled] .checkbox,fieldset[disabled] .radio{color:#7a7a7a;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#485fc7;right:1.125em;z-index:4}.select.is-rounded select{border-radius:9999px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:0}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select.is-hovered,.select.is-white select:hover{border-color:#f2f2f2}.select.is-white select.is-active,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select.is-hovered,.select.is-black select:hover{border-color:#000}.select.is-black select.is-active,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select.is-hovered,.select.is-light select:hover{border-color:#e8e8e8}.select.is-light select.is-active,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.select.is-dark:not(:hover)::after{border-color:#363636}.select.is-dark select{border-color:#363636}.select.is-dark select.is-hovered,.select.is-dark select:hover{border-color:#292929}.select.is-dark select.is-active,.select.is-dark select.is-focused,.select.is-dark select:active,.select.is-dark select:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.select.is-primary:not(:hover)::after{border-color:#00d1b2}.select.is-primary select{border-color:#00d1b2}.select.is-primary select.is-hovered,.select.is-primary select:hover{border-color:#00b89c}.select.is-primary select.is-active,.select.is-primary select.is-focused,.select.is-primary select:active,.select.is-primary select:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.select.is-link:not(:hover)::after{border-color:#485fc7}.select.is-link select{border-color:#485fc7}.select.is-link select.is-hovered,.select.is-link select:hover{border-color:#3a51bb}.select.is-link select.is-active,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.select.is-info:not(:hover)::after{border-color:#3e8ed0}.select.is-info select{border-color:#3e8ed0}.select.is-info select.is-hovered,.select.is-info select:hover{border-color:#3082c5}.select.is-info select.is-active,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.select.is-success:not(:hover)::after{border-color:#48c78e}.select.is-success select{border-color:#48c78e}.select.is-success select.is-hovered,.select.is-success select:hover{border-color:#3abb81}.select.is-success select.is-active,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.select.is-warning:not(:hover)::after{border-color:#ffe08a}.select.is-warning select{border-color:#ffe08a}.select.is-warning select.is-hovered,.select.is-warning select:hover{border-color:#ffd970}.select.is-warning select.is-active,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.select.is-danger:not(:hover)::after{border-color:#f14668}.select.is-danger select{border-color:#f14668}.select.is-danger select.is-hovered,.select.is-danger select:hover{border-color:#ef2e55}.select.is-danger select.is-active,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.select.is-small{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#7a7a7a!important;opacity:.5}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:.625em;transform:none}.select.is-loading.is-small:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white.is-hovered .file-cta,.file.is-white:hover .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white.is-focused .file-cta,.file.is-white:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,255,255,.25);color:#0a0a0a}.file.is-white.is-active .file-cta,.file.is-white:active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black.is-hovered .file-cta,.file.is-black:hover .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black.is-focused .file-cta,.file.is-black:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(10,10,10,.25);color:#fff}.file.is-black.is-active .file-cta,.file.is-black:active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-hovered .file-cta,.file.is-light:hover .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-focused .file-cta,.file.is-light:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(245,245,245,.25);color:rgba(0,0,0,.7)}.file.is-light.is-active .file-cta,.file.is-light:active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-dark .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark.is-hovered .file-cta,.file.is-dark:hover .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark.is-focused .file-cta,.file.is-dark:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(54,54,54,.25);color:#fff}.file.is-dark.is-active .file-cta,.file.is-dark:active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta{background-color:#00d1b2;border-color:transparent;color:#fff}.file.is-primary.is-hovered .file-cta,.file.is-primary:hover .file-cta{background-color:#00c4a7;border-color:transparent;color:#fff}.file.is-primary.is-focused .file-cta,.file.is-primary:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(0,209,178,.25);color:#fff}.file.is-primary.is-active .file-cta,.file.is-primary:active .file-cta{background-color:#00b89c;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#485fc7;border-color:transparent;color:#fff}.file.is-link.is-hovered .file-cta,.file.is-link:hover .file-cta{background-color:#3e56c4;border-color:transparent;color:#fff}.file.is-link.is-focused .file-cta,.file.is-link:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,95,199,.25);color:#fff}.file.is-link.is-active .file-cta,.file.is-link:active .file-cta{background-color:#3a51bb;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#3e8ed0;border-color:transparent;color:#fff}.file.is-info.is-hovered .file-cta,.file.is-info:hover .file-cta{background-color:#3488ce;border-color:transparent;color:#fff}.file.is-info.is-focused .file-cta,.file.is-info:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(62,142,208,.25);color:#fff}.file.is-info.is-active .file-cta,.file.is-info:active .file-cta{background-color:#3082c5;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#48c78e;border-color:transparent;color:#fff}.file.is-success.is-hovered .file-cta,.file.is-success:hover .file-cta{background-color:#3ec487;border-color:transparent;color:#fff}.file.is-success.is-focused .file-cta,.file.is-success:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,199,142,.25);color:#fff}.file.is-success.is-active .file-cta,.file.is-success:active .file-cta{background-color:#3abb81;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-hovered .file-cta,.file.is-warning:hover .file-cta{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-focused .file-cta,.file.is-warning:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,224,138,.25);color:rgba(0,0,0,.7)}.file.is-warning.is-active .file-cta,.file.is-warning:active .file-cta{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-danger .file-cta{background-color:#f14668;border-color:transparent;color:#fff}.file.is-danger.is-hovered .file-cta,.file.is-danger:hover .file-cta{background-color:#f03a5f;border-color:transparent;color:#fff}.file.is-danger.is-focused .file-cta,.file.is-danger:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(241,70,104,.25);color:#fff}.file.is-danger.is-active .file-cta,.file.is-danger:active .file-cta{background-color:#ef2e55;border-color:transparent;color:#fff}.file.is-small{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:0;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:.5em}.label.is-small{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark{color:#363636}.help.is-primary{color:#00d1b2}.help.is-link{color:#485fc7}.help.is-info{color:#3e8ed0}.help.is-success{color:#48c78e}.help.is-warning{color:#ffe08a}.help.is-danger{color:#f14668}.field:not(:last-child){margin-bottom:.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]).is-hovered,.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .input:not([disabled]).is-hovered,.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]).is-hovered,.field.has-addons .control .select select:not([disabled]):hover{z-index:2}.field.has-addons .control .button:not([disabled]).is-active,.field.has-addons .control .button:not([disabled]).is-focused,.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .input:not([disabled]).is-active,.field.has-addons .control .input:not([disabled]).is-focused,.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control .select select:not([disabled]).is-active,.field.has-addons .control .select select:not([disabled]).is-focused,.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select:not([disabled]):focus{z-index:3}.field.has-addons .control .button:not([disabled]).is-active:hover,.field.has-addons .control .button:not([disabled]).is-focused:hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .input:not([disabled]).is-active:hover,.field.has-addons .control .input:not([disabled]).is-focused:hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control .select select:not([disabled]).is-active:hover,.field.has-addons .control .select select:not([disabled]).is-focused:hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select:not([disabled]):focus:hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width:769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width:768px){.field-label{margin-bottom:.5rem}}@media screen and (min-width:769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:.375em}.field-label.is-normal{padding-top:.375em}.field-label.is-medium{font-size:1.25rem;padding-top:.375em}.field-label.is-large{font-size:1.5rem;padding-top:.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width:769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#4a4a4a}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute!important;right:.625em;top:.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#485fc7;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ol,.breadcrumb ul{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;max-width:100%;position:relative}.card-content:first-child,.card-footer:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-content:last-child,.card-footer:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:transparent;align-items:stretch;box-shadow:0 .125em .25em rgba(10,10,10,.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:transparent;padding:1.5rem}.card-footer{background-color:transparent;border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:.875rem;line-height:1.5;padding:.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#485fc7;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width:769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .subtitle,.level-item .title{margin-bottom:0}@media screen and (max-width:768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width:769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width:768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width:769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width:769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width:768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:.5em .75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#485fc7;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#7a7a7a;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body{border-color:#363636}.message.is-primary{background-color:#ebfffc}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#00947e}.message.is-link{background-color:#eff1fa}.message.is-link .message-header{background-color:#485fc7;color:#fff}.message.is-link .message-body{border-color:#485fc7;color:#3850b7}.message.is-info{background-color:#eff5fb}.message.is-info .message-header{background-color:#3e8ed0;color:#fff}.message.is-info .message-body{border-color:#3e8ed0;color:#296fa8}.message.is-success{background-color:#effaf5}.message.is-success .message-header{background-color:#48c78e;color:#fff}.message.is-success .message-body{border-color:#48c78e;color:#257953}.message.is-warning{background-color:#fffaeb}.message.is-warning .message-header{background-color:#ffe08a;color:rgba(0,0,0,.7)}.message.is-warning .message-body{border-color:#ffe08a;color:#946c00}.message.is-danger{background-color:#feecf0}.message.is-danger .message-header{background-color:#f14668;color:#fff}.message.is-danger .message-body{border-color:#f14668;color:#cc0f35}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:transparent}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,.86)}.modal-card,.modal-content{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width:769px){.modal-card,.modal-content{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:0 0;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-foot,.modal-card-head{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link,.navbar.is-white .navbar-brand>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width:1024px){.navbar.is-white .navbar-end .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-start>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link::after,.navbar.is-white .navbar-start .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand .navbar-link,.navbar.is-black .navbar-brand>.navbar-item{color:#fff}.navbar.is-black .navbar-brand .navbar-link.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-black .navbar-end .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-start>.navbar-item{color:#fff}.navbar.is-black .navbar-end .navbar-link.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-end .navbar-link::after,.navbar.is-black .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link,.navbar.is-light .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-light .navbar-end .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link::after,.navbar.is-light .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,.7)}}.navbar.is-dark{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand .navbar-link,.navbar.is-dark .navbar-brand>.navbar-item{color:#fff}.navbar.is-dark .navbar-brand .navbar-link.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-dark .navbar-end .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-start>.navbar-item{color:#fff}.navbar.is-dark .navbar-end .navbar-link.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-end .navbar-link::after,.navbar.is-dark .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand .navbar-link,.navbar.is-primary .navbar-brand>.navbar-item{color:#fff}.navbar.is-primary .navbar-brand .navbar-link.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-primary .navbar-end .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-start>.navbar-item{color:#fff}.navbar.is-primary .navbar-end .navbar-link.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-end .navbar-link::after,.navbar.is-primary .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#485fc7;color:#fff}.navbar.is-link .navbar-brand .navbar-link,.navbar.is-link .navbar-brand>.navbar-item{color:#fff}.navbar.is-link .navbar-brand .navbar-link.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-link .navbar-end .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-start>.navbar-item{color:#fff}.navbar.is-link .navbar-end .navbar-link.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-end .navbar-link::after,.navbar.is-link .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#485fc7;color:#fff}}.navbar.is-info{background-color:#3e8ed0;color:#fff}.navbar.is-info .navbar-brand .navbar-link,.navbar.is-info .navbar-brand>.navbar-item{color:#fff}.navbar.is-info .navbar-brand .navbar-link.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-info .navbar-end .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-start>.navbar-item{color:#fff}.navbar.is-info .navbar-end .navbar-link.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-end .navbar-link::after,.navbar.is-info .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#3e8ed0;color:#fff}}.navbar.is-success{background-color:#48c78e;color:#fff}.navbar.is-success .navbar-brand .navbar-link,.navbar.is-success .navbar-brand>.navbar-item{color:#fff}.navbar.is-success .navbar-brand .navbar-link.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-success .navbar-end .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-start>.navbar-item{color:#fff}.navbar.is-success .navbar-end .navbar-link.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-end .navbar-link::after,.navbar.is-success .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#48c78e;color:#fff}}.navbar.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link,.navbar.is-warning .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-warning .navbar-end .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link::after,.navbar.is-warning .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffe08a;color:rgba(0,0,0,.7)}}.navbar.is-danger{background-color:#f14668;color:#fff}.navbar.is-danger .navbar-brand .navbar-link,.navbar.is-danger .navbar-brand>.navbar-item{color:#fff}.navbar.is-danger .navbar-brand .navbar-link.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-danger .navbar-end .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-start>.navbar-item{color:#fff}.navbar.is-danger .navbar-end .navbar-link.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-end .navbar-link::after,.navbar.is-danger .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#f14668;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}body.has-navbar-fixed-top,html.has-navbar-fixed-top{padding-top:3.25rem}body.has-navbar-fixed-bottom,html.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color,opacity,transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:first-child{top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,.05)}.navbar-burger.is-active span:first-child{transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:.5rem .75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-.25rem;margin-right:-.25rem}.navbar-link,a.navbar-item{cursor:pointer}.navbar-link.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,a.navbar-item.is-active,a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover{background-color:#fafafa;color:#485fc7}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:transparent;border-bottom-color:#485fc7}.navbar-item.is-tab.is-active{background-color:transparent;border-bottom-color:#485fc7;border-bottom-style:solid;border-bottom-width:3px;color:#485fc7;padding-bottom:calc(.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#485fc7;margin-top:-.375em;right:1.125em}.navbar-dropdown{font-size:.875rem;padding-bottom:.5rem;padding-top:.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:.5rem 0}@media screen and (max-width:1023px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,.1);padding:.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}body.has-navbar-fixed-top-touch,html.has-navbar-fixed-top-touch{padding-top:3.25rem}body.has-navbar-fixed-bottom-touch,html.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width:1024px){.navbar,.navbar-end,.navbar-menu,.navbar-start{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-end,.navbar.is-spaced .navbar-start{align-items:center}.navbar.is-spaced .navbar-link,.navbar.is-spaced a.navbar-item{border-radius:4px}.navbar.is-transparent .navbar-link.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover{background-color:transparent!important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent!important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(.25em,-.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,.1);display:none;font-size:.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-dropdown{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity,transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.container>.navbar .navbar-brand,.navbar>.container .navbar-brand{margin-left:-.75rem}.container>.navbar .navbar-menu,.navbar>.container .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-desktop{top:0}body.has-navbar-fixed-top-desktop,html.has-navbar-fixed-top-desktop{padding-top:3.25rem}body.has-navbar-fixed-bottom-desktop,html.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}body.has-spaced-navbar-fixed-top,html.has-spaced-navbar-fixed-top{padding-top:5.25rem}body.has-spaced-navbar-fixed-bottom,html.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}.navbar-link.is-active,a.navbar-item.is-active{color:#0a0a0a}.navbar-link.is-active:not(:focus):not(:hover),a.navbar-item.is-active:not(:focus):not(:hover){background-color:transparent}.navbar-item.has-dropdown.is-active .navbar-link,.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-next,.pagination.is-rounded .pagination-previous{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-link,.pagination-next,.pagination-previous{border-color:#dbdbdb;color:#363636;min-width:2.5em}.pagination-link:hover,.pagination-next:hover,.pagination-previous:hover{border-color:#b5b5b5;color:#363636}.pagination-link:focus,.pagination-next:focus,.pagination-previous:focus{border-color:#485fc7}.pagination-link:active,.pagination-next:active,.pagination-previous:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2)}.pagination-link.is-disabled,.pagination-link[disabled],.pagination-next.is-disabled,.pagination-next[disabled],.pagination-previous.is-disabled,.pagination-previous[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:.5}.pagination-next,.pagination-previous{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#485fc7;border-color:#485fc7;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width:768px){.pagination{flex-wrap:wrap}.pagination-next,.pagination-previous{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width:769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading{background-color:#00d1b2;color:#fff}.panel.is-primary .panel-tabs a.is-active{border-bottom-color:#00d1b2}.panel.is-primary .panel-block.is-active .panel-icon{color:#00d1b2}.panel.is-link .panel-heading{background-color:#485fc7;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#485fc7}.panel.is-link .panel-block.is-active .panel-icon{color:#485fc7}.panel.is-info .panel-heading{background-color:#3e8ed0;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#3e8ed0}.panel.is-info .panel-block.is-active .panel-icon{color:#3e8ed0}.panel.is-success .panel-heading{background-color:#48c78e;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#48c78e}.panel.is-success .panel-block.is-active .panel-icon{color:#48c78e}.panel.is-warning .panel-heading{background-color:#ffe08a;color:rgba(0,0,0,.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffe08a}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffe08a}.panel.is-danger .panel-heading{background-color:#f14668;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#f14668}.panel.is-danger .panel-block.is-active .panel-icon{color:#f14668}.panel-block:not(:last-child),.panel-tabs:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#363636;font-size:1.25em;font-weight:700;line-height:1.25;padding:.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#485fc7}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:.5em .75em}.panel-block input[type=checkbox]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#485fc7;color:#363636}.panel-block.is-active .panel-icon{color:#485fc7}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#485fc7;color:#485fc7}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:.75em;padding-right:.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:transparent!important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li.is-active a{background-color:#485fc7;border-color:#485fc7;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width:768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-left:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-left:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-left:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-left:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-left:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-left:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-left:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-left:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width:769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width:1023px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-left:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-left:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-left:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-left:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-left:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-left:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-left:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-left:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width:1024px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-left:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-left:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-left:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-left:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-left:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-left:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-left:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-left:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width:1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-left:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-left:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-left:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-left:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-left:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-left:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-left:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-left:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width:1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-left:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-left:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-left:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-left:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-left:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-left:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-left:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-left:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0!important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width:769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width:1024px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap:0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap:0rem}@media screen and (max-width:768px){.columns.is-variable.is-0-mobile{--columnGap:0rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-0-tablet{--columnGap:0rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-0-tablet-only{--columnGap:0rem}}@media screen and (max-width:1023px){.columns.is-variable.is-0-touch{--columnGap:0rem}}@media screen and (min-width:1024px){.columns.is-variable.is-0-desktop{--columnGap:0rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-0-desktop-only{--columnGap:0rem}}@media screen and (min-width:1216px){.columns.is-variable.is-0-widescreen{--columnGap:0rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-0-widescreen-only{--columnGap:0rem}}@media screen and (min-width:1408px){.columns.is-variable.is-0-fullhd{--columnGap:0rem}}.columns.is-variable.is-1{--columnGap:0.25rem}@media screen and (max-width:768px){.columns.is-variable.is-1-mobile{--columnGap:0.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-1-tablet{--columnGap:0.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-1-tablet-only{--columnGap:0.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-1-touch{--columnGap:0.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-1-desktop{--columnGap:0.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-1-desktop-only{--columnGap:0.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-1-widescreen{--columnGap:0.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-1-widescreen-only{--columnGap:0.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-1-fullhd{--columnGap:0.25rem}}.columns.is-variable.is-2{--columnGap:0.5rem}@media screen and (max-width:768px){.columns.is-variable.is-2-mobile{--columnGap:0.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-2-tablet{--columnGap:0.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-2-tablet-only{--columnGap:0.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-2-touch{--columnGap:0.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-2-desktop{--columnGap:0.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-2-desktop-only{--columnGap:0.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-2-widescreen{--columnGap:0.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-2-widescreen-only{--columnGap:0.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-2-fullhd{--columnGap:0.5rem}}.columns.is-variable.is-3{--columnGap:0.75rem}@media screen and (max-width:768px){.columns.is-variable.is-3-mobile{--columnGap:0.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-3-tablet{--columnGap:0.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-3-tablet-only{--columnGap:0.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-3-touch{--columnGap:0.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-3-desktop{--columnGap:0.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-3-desktop-only{--columnGap:0.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-3-widescreen{--columnGap:0.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-3-widescreen-only{--columnGap:0.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-3-fullhd{--columnGap:0.75rem}}.columns.is-variable.is-4{--columnGap:1rem}@media screen and (max-width:768px){.columns.is-variable.is-4-mobile{--columnGap:1rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-4-tablet{--columnGap:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-4-tablet-only{--columnGap:1rem}}@media screen and (max-width:1023px){.columns.is-variable.is-4-touch{--columnGap:1rem}}@media screen and (min-width:1024px){.columns.is-variable.is-4-desktop{--columnGap:1rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-4-desktop-only{--columnGap:1rem}}@media screen and (min-width:1216px){.columns.is-variable.is-4-widescreen{--columnGap:1rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-4-widescreen-only{--columnGap:1rem}}@media screen and (min-width:1408px){.columns.is-variable.is-4-fullhd{--columnGap:1rem}}.columns.is-variable.is-5{--columnGap:1.25rem}@media screen and (max-width:768px){.columns.is-variable.is-5-mobile{--columnGap:1.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-5-tablet{--columnGap:1.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-5-tablet-only{--columnGap:1.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-5-touch{--columnGap:1.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-5-desktop{--columnGap:1.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-5-desktop-only{--columnGap:1.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-5-widescreen{--columnGap:1.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-5-widescreen-only{--columnGap:1.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-5-fullhd{--columnGap:1.25rem}}.columns.is-variable.is-6{--columnGap:1.5rem}@media screen and (max-width:768px){.columns.is-variable.is-6-mobile{--columnGap:1.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-6-tablet{--columnGap:1.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-6-tablet-only{--columnGap:1.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-6-touch{--columnGap:1.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-6-desktop{--columnGap:1.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-6-desktop-only{--columnGap:1.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-6-widescreen{--columnGap:1.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-6-widescreen-only{--columnGap:1.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-6-fullhd{--columnGap:1.5rem}}.columns.is-variable.is-7{--columnGap:1.75rem}@media screen and (max-width:768px){.columns.is-variable.is-7-mobile{--columnGap:1.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-7-tablet{--columnGap:1.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-7-tablet-only{--columnGap:1.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-7-touch{--columnGap:1.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-7-desktop{--columnGap:1.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-7-desktop-only{--columnGap:1.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-7-widescreen{--columnGap:1.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-7-widescreen-only{--columnGap:1.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-7-fullhd{--columnGap:1.75rem}}.columns.is-variable.is-8{--columnGap:2rem}@media screen and (max-width:768px){.columns.is-variable.is-8-mobile{--columnGap:2rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-8-tablet{--columnGap:2rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-8-tablet-only{--columnGap:2rem}}@media screen and (max-width:1023px){.columns.is-variable.is-8-touch{--columnGap:2rem}}@media screen and (min-width:1024px){.columns.is-variable.is-8-desktop{--columnGap:2rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-8-desktop-only{--columnGap:2rem}}@media screen and (min-width:1216px){.columns.is-variable.is-8-widescreen{--columnGap:2rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-8-widescreen-only{--columnGap:2rem}}@media screen and (min-width:1408px){.columns.is-variable.is-8-fullhd{--columnGap:2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:-webkit-min-content;min-height:-moz-min-content;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0!important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem!important}@media screen and (min-width:769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.has-text-white{color:#fff!important}a.has-text-white:focus,a.has-text-white:hover{color:#e6e6e6!important}.has-background-white{background-color:#fff!important}.has-text-black{color:#0a0a0a!important}a.has-text-black:focus,a.has-text-black:hover{color:#000!important}.has-background-black{background-color:#0a0a0a!important}.has-text-light{color:#f5f5f5!important}a.has-text-light:focus,a.has-text-light:hover{color:#dbdbdb!important}.has-background-light{background-color:#f5f5f5!important}.has-text-dark{color:#363636!important}a.has-text-dark:focus,a.has-text-dark:hover{color:#1c1c1c!important}.has-background-dark{background-color:#363636!important}.has-text-primary{color:#00d1b2!important}a.has-text-primary:focus,a.has-text-primary:hover{color:#009e86!important}.has-background-primary{background-color:#00d1b2!important}.has-text-primary-light{color:#ebfffc!important}a.has-text-primary-light:focus,a.has-text-primary-light:hover{color:#b8fff4!important}.has-background-primary-light{background-color:#ebfffc!important}.has-text-primary-dark{color:#00947e!important}a.has-text-primary-dark:focus,a.has-text-primary-dark:hover{color:#00c7a9!important}.has-background-primary-dark{background-color:#00947e!important}.has-text-link{color:#485fc7!important}a.has-text-link:focus,a.has-text-link:hover{color:#3449a8!important}.has-background-link{background-color:#485fc7!important}.has-text-link-light{color:#eff1fa!important}a.has-text-link-light:focus,a.has-text-link-light:hover{color:#c8cfee!important}.has-background-link-light{background-color:#eff1fa!important}.has-text-link-dark{color:#3850b7!important}a.has-text-link-dark:focus,a.has-text-link-dark:hover{color:#576dcb!important}.has-background-link-dark{background-color:#3850b7!important}.has-text-info{color:#3e8ed0!important}a.has-text-info:focus,a.has-text-info:hover{color:#2b74b1!important}.has-background-info{background-color:#3e8ed0!important}.has-text-info-light{color:#eff5fb!important}a.has-text-info-light:focus,a.has-text-info-light:hover{color:#c6ddf1!important}.has-background-info-light{background-color:#eff5fb!important}.has-text-info-dark{color:#296fa8!important}a.has-text-info-dark:focus,a.has-text-info-dark:hover{color:#368ace!important}.has-background-info-dark{background-color:#296fa8!important}.has-text-success{color:#48c78e!important}a.has-text-success:focus,a.has-text-success:hover{color:#34a873!important}.has-background-success{background-color:#48c78e!important}.has-text-success-light{color:#effaf5!important}a.has-text-success-light:focus,a.has-text-success-light:hover{color:#c8eedd!important}.has-background-success-light{background-color:#effaf5!important}.has-text-success-dark{color:#257953!important}a.has-text-success-dark:focus,a.has-text-success-dark:hover{color:#31a06e!important}.has-background-success-dark{background-color:#257953!important}.has-text-warning{color:#ffe08a!important}a.has-text-warning:focus,a.has-text-warning:hover{color:#ffd257!important}.has-background-warning{background-color:#ffe08a!important}.has-text-warning-light{color:#fffaeb!important}a.has-text-warning-light:focus,a.has-text-warning-light:hover{color:#ffecb8!important}.has-background-warning-light{background-color:#fffaeb!important}.has-text-warning-dark{color:#946c00!important}a.has-text-warning-dark:focus,a.has-text-warning-dark:hover{color:#c79200!important}.has-background-warning-dark{background-color:#946c00!important}.has-text-danger{color:#f14668!important}a.has-text-danger:focus,a.has-text-danger:hover{color:#ee1742!important}.has-background-danger{background-color:#f14668!important}.has-text-danger-light{color:#feecf0!important}a.has-text-danger-light:focus,a.has-text-danger-light:hover{color:#fabdc9!important}.has-background-danger-light{background-color:#feecf0!important}.has-text-danger-dark{color:#cc0f35!important}a.has-text-danger-dark:focus,a.has-text-danger-dark:hover{color:#ee2049!important}.has-background-danger-dark{background-color:#cc0f35!important}.has-text-black-bis{color:#121212!important}.has-background-black-bis{background-color:#121212!important}.has-text-black-ter{color:#242424!important}.has-background-black-ter{background-color:#242424!important}.has-text-grey-darker{color:#363636!important}.has-background-grey-darker{background-color:#363636!important}.has-text-grey-dark{color:#4a4a4a!important}.has-background-grey-dark{background-color:#4a4a4a!important}.has-text-grey{color:#7a7a7a!important}.has-background-grey{background-color:#7a7a7a!important}.has-text-grey-light{color:#b5b5b5!important}.has-background-grey-light{background-color:#b5b5b5!important}.has-text-grey-lighter{color:#dbdbdb!important}.has-background-grey-lighter{background-color:#dbdbdb!important}.has-text-white-ter{color:#f5f5f5!important}.has-background-white-ter{background-color:#f5f5f5!important}.has-text-white-bis{color:#fafafa!important}.has-background-white-bis{background-color:#fafafa!important}.is-flex-direction-row{flex-direction:row!important}.is-flex-direction-row-reverse{flex-direction:row-reverse!important}.is-flex-direction-column{flex-direction:column!important}.is-flex-direction-column-reverse{flex-direction:column-reverse!important}.is-flex-wrap-nowrap{flex-wrap:nowrap!important}.is-flex-wrap-wrap{flex-wrap:wrap!important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse!important}.is-justify-content-flex-start{justify-content:flex-start!important}.is-justify-content-flex-end{justify-content:flex-end!important}.is-justify-content-center{justify-content:center!important}.is-justify-content-space-between{justify-content:space-between!important}.is-justify-content-space-around{justify-content:space-around!important}.is-justify-content-space-evenly{justify-content:space-evenly!important}.is-justify-content-start{justify-content:start!important}.is-justify-content-end{justify-content:end!important}.is-justify-content-left{justify-content:left!important}.is-justify-content-right{justify-content:right!important}.is-align-content-flex-start{align-content:flex-start!important}.is-align-content-flex-end{align-content:flex-end!important}.is-align-content-center{align-content:center!important}.is-align-content-space-between{align-content:space-between!important}.is-align-content-space-around{align-content:space-around!important}.is-align-content-space-evenly{align-content:space-evenly!important}.is-align-content-stretch{align-content:stretch!important}.is-align-content-start{align-content:start!important}.is-align-content-end{align-content:end!important}.is-align-content-baseline{align-content:baseline!important}.is-align-items-stretch{align-items:stretch!important}.is-align-items-flex-start{align-items:flex-start!important}.is-align-items-flex-end{align-items:flex-end!important}.is-align-items-center{align-items:center!important}.is-align-items-baseline{align-items:baseline!important}.is-align-items-start{align-items:start!important}.is-align-items-end{align-items:end!important}.is-align-items-self-start{align-items:self-start!important}.is-align-items-self-end{align-items:self-end!important}.is-align-self-auto{align-self:auto!important}.is-align-self-flex-start{align-self:flex-start!important}.is-align-self-flex-end{align-self:flex-end!important}.is-align-self-center{align-self:center!important}.is-align-self-baseline{align-self:baseline!important}.is-align-self-stretch{align-self:stretch!important}.is-flex-grow-0{flex-grow:0!important}.is-flex-grow-1{flex-grow:1!important}.is-flex-grow-2{flex-grow:2!important}.is-flex-grow-3{flex-grow:3!important}.is-flex-grow-4{flex-grow:4!important}.is-flex-grow-5{flex-grow:5!important}.is-flex-shrink-0{flex-shrink:0!important}.is-flex-shrink-1{flex-shrink:1!important}.is-flex-shrink-2{flex-shrink:2!important}.is-flex-shrink-3{flex-shrink:3!important}.is-flex-shrink-4{flex-shrink:4!important}.is-flex-shrink-5{flex-shrink:5!important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left!important}.is-pulled-right{float:right!important}.is-radiusless{border-radius:0!important}.is-shadowless{box-shadow:none!important}.is-clickable{cursor:pointer!important;pointer-events:all!important}.is-clipped{overflow:hidden!important}.is-relative{position:relative!important}.is-marginless{margin:0!important}.is-paddingless{padding:0!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:.75rem!important}.mt-3{margin-top:.75rem!important}.mr-3{margin-right:.75rem!important}.mb-3{margin-bottom:.75rem!important}.ml-3{margin-left:.75rem!important}.mx-3{margin-left:.75rem!important;margin-right:.75rem!important}.my-3{margin-top:.75rem!important;margin-bottom:.75rem!important}.m-4{margin:1rem!important}.mt-4{margin-top:1rem!important}.mr-4{margin-right:1rem!important}.mb-4{margin-bottom:1rem!important}.ml-4{margin-left:1rem!important}.mx-4{margin-left:1rem!important;margin-right:1rem!important}.my-4{margin-top:1rem!important;margin-bottom:1rem!important}.m-5{margin:1.5rem!important}.mt-5{margin-top:1.5rem!important}.mr-5{margin-right:1.5rem!important}.mb-5{margin-bottom:1.5rem!important}.ml-5{margin-left:1.5rem!important}.mx-5{margin-left:1.5rem!important;margin-right:1.5rem!important}.my-5{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-6{margin:3rem!important}.mt-6{margin-top:3rem!important}.mr-6{margin-right:3rem!important}.mb-6{margin-bottom:3rem!important}.ml-6{margin-left:3rem!important}.mx-6{margin-left:3rem!important;margin-right:3rem!important}.my-6{margin-top:3rem!important;margin-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:.75rem!important}.pt-3{padding-top:.75rem!important}.pr-3{padding-right:.75rem!important}.pb-3{padding-bottom:.75rem!important}.pl-3{padding-left:.75rem!important}.px-3{padding-left:.75rem!important;padding-right:.75rem!important}.py-3{padding-top:.75rem!important;padding-bottom:.75rem!important}.p-4{padding:1rem!important}.pt-4{padding-top:1rem!important}.pr-4{padding-right:1rem!important}.pb-4{padding-bottom:1rem!important}.pl-4{padding-left:1rem!important}.px-4{padding-left:1rem!important;padding-right:1rem!important}.py-4{padding-top:1rem!important;padding-bottom:1rem!important}.p-5{padding:1.5rem!important}.pt-5{padding-top:1.5rem!important}.pr-5{padding-right:1.5rem!important}.pb-5{padding-bottom:1.5rem!important}.pl-5{padding-left:1.5rem!important}.px-5{padding-left:1.5rem!important;padding-right:1.5rem!important}.py-5{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-6{padding:3rem!important}.pt-6{padding-top:3rem!important}.pr-6{padding-right:3rem!important}.pb-6{padding-bottom:3rem!important}.pl-6{padding-left:3rem!important}.px-6{padding-left:3rem!important;padding-right:3rem!important}.py-6{padding-top:3rem!important;padding-bottom:3rem!important}.p-auto{padding:auto!important}.pt-auto{padding-top:auto!important}.pr-auto{padding-right:auto!important}.pb-auto{padding-bottom:auto!important}.pl-auto{padding-left:auto!important}.px-auto{padding-left:auto!important;padding-right:auto!important}.py-auto{padding-top:auto!important;padding-bottom:auto!important}.is-size-1{font-size:3rem!important}.is-size-2{font-size:2.5rem!important}.is-size-3{font-size:2rem!important}.is-size-4{font-size:1.5rem!important}.is-size-5{font-size:1.25rem!important}.is-size-6{font-size:1rem!important}.is-size-7{font-size:.75rem!important}@media screen and (max-width:768px){.is-size-1-mobile{font-size:3rem!important}.is-size-2-mobile{font-size:2.5rem!important}.is-size-3-mobile{font-size:2rem!important}.is-size-4-mobile{font-size:1.5rem!important}.is-size-5-mobile{font-size:1.25rem!important}.is-size-6-mobile{font-size:1rem!important}.is-size-7-mobile{font-size:.75rem!important}}@media screen and (min-width:769px),print{.is-size-1-tablet{font-size:3rem!important}.is-size-2-tablet{font-size:2.5rem!important}.is-size-3-tablet{font-size:2rem!important}.is-size-4-tablet{font-size:1.5rem!important}.is-size-5-tablet{font-size:1.25rem!important}.is-size-6-tablet{font-size:1rem!important}.is-size-7-tablet{font-size:.75rem!important}}@media screen and (max-width:1023px){.is-size-1-touch{font-size:3rem!important}.is-size-2-touch{font-size:2.5rem!important}.is-size-3-touch{font-size:2rem!important}.is-size-4-touch{font-size:1.5rem!important}.is-size-5-touch{font-size:1.25rem!important}.is-size-6-touch{font-size:1rem!important}.is-size-7-touch{font-size:.75rem!important}}@media screen and (min-width:1024px){.is-size-1-desktop{font-size:3rem!important}.is-size-2-desktop{font-size:2.5rem!important}.is-size-3-desktop{font-size:2rem!important}.is-size-4-desktop{font-size:1.5rem!important}.is-size-5-desktop{font-size:1.25rem!important}.is-size-6-desktop{font-size:1rem!important}.is-size-7-desktop{font-size:.75rem!important}}@media screen and (min-width:1216px){.is-size-1-widescreen{font-size:3rem!important}.is-size-2-widescreen{font-size:2.5rem!important}.is-size-3-widescreen{font-size:2rem!important}.is-size-4-widescreen{font-size:1.5rem!important}.is-size-5-widescreen{font-size:1.25rem!important}.is-size-6-widescreen{font-size:1rem!important}.is-size-7-widescreen{font-size:.75rem!important}}@media screen and (min-width:1408px){.is-size-1-fullhd{font-size:3rem!important}.is-size-2-fullhd{font-size:2.5rem!important}.is-size-3-fullhd{font-size:2rem!important}.is-size-4-fullhd{font-size:1.5rem!important}.is-size-5-fullhd{font-size:1.25rem!important}.is-size-6-fullhd{font-size:1rem!important}.is-size-7-fullhd{font-size:.75rem!important}}.has-text-centered{text-align:center!important}.has-text-justified{text-align:justify!important}.has-text-left{text-align:left!important}.has-text-right{text-align:right!important}@media screen and (max-width:768px){.has-text-centered-mobile{text-align:center!important}}@media screen and (min-width:769px),print{.has-text-centered-tablet{text-align:center!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-centered-tablet-only{text-align:center!important}}@media screen and (max-width:1023px){.has-text-centered-touch{text-align:center!important}}@media screen and (min-width:1024px){.has-text-centered-desktop{text-align:center!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-centered-desktop-only{text-align:center!important}}@media screen and (min-width:1216px){.has-text-centered-widescreen{text-align:center!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-centered-widescreen-only{text-align:center!important}}@media screen and (min-width:1408px){.has-text-centered-fullhd{text-align:center!important}}@media screen and (max-width:768px){.has-text-justified-mobile{text-align:justify!important}}@media screen and (min-width:769px),print{.has-text-justified-tablet{text-align:justify!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-justified-tablet-only{text-align:justify!important}}@media screen and (max-width:1023px){.has-text-justified-touch{text-align:justify!important}}@media screen and (min-width:1024px){.has-text-justified-desktop{text-align:justify!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-justified-desktop-only{text-align:justify!important}}@media screen and (min-width:1216px){.has-text-justified-widescreen{text-align:justify!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-justified-widescreen-only{text-align:justify!important}}@media screen and (min-width:1408px){.has-text-justified-fullhd{text-align:justify!important}}@media screen and (max-width:768px){.has-text-left-mobile{text-align:left!important}}@media screen and (min-width:769px),print{.has-text-left-tablet{text-align:left!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-left-tablet-only{text-align:left!important}}@media screen and (max-width:1023px){.has-text-left-touch{text-align:left!important}}@media screen and (min-width:1024px){.has-text-left-desktop{text-align:left!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-left-desktop-only{text-align:left!important}}@media screen and (min-width:1216px){.has-text-left-widescreen{text-align:left!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-left-widescreen-only{text-align:left!important}}@media screen and (min-width:1408px){.has-text-left-fullhd{text-align:left!important}}@media screen and (max-width:768px){.has-text-right-mobile{text-align:right!important}}@media screen and (min-width:769px),print{.has-text-right-tablet{text-align:right!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-right-tablet-only{text-align:right!important}}@media screen and (max-width:1023px){.has-text-right-touch{text-align:right!important}}@media screen and (min-width:1024px){.has-text-right-desktop{text-align:right!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-right-desktop-only{text-align:right!important}}@media screen and (min-width:1216px){.has-text-right-widescreen{text-align:right!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-right-widescreen-only{text-align:right!important}}@media screen and (min-width:1408px){.has-text-right-fullhd{text-align:right!important}}.is-capitalized{text-transform:capitalize!important}.is-lowercase{text-transform:lowercase!important}.is-uppercase{text-transform:uppercase!important}.is-italic{font-style:italic!important}.is-underlined{text-decoration:underline!important}.has-text-weight-light{font-weight:300!important}.has-text-weight-normal{font-weight:400!important}.has-text-weight-medium{font-weight:500!important}.has-text-weight-semibold{font-weight:600!important}.has-text-weight-bold{font-weight:700!important}.is-family-primary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-secondary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-sans-serif{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-monospace{font-family:monospace!important}.is-family-code{font-family:monospace!important}.is-block{display:block!important}@media screen and (max-width:768px){.is-block-mobile{display:block!important}}@media screen and (min-width:769px),print{.is-block-tablet{display:block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-block-tablet-only{display:block!important}}@media screen and (max-width:1023px){.is-block-touch{display:block!important}}@media screen and (min-width:1024px){.is-block-desktop{display:block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-block-desktop-only{display:block!important}}@media screen and (min-width:1216px){.is-block-widescreen{display:block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-block-widescreen-only{display:block!important}}@media screen and (min-width:1408px){.is-block-fullhd{display:block!important}}.is-flex{display:flex!important}@media screen and (max-width:768px){.is-flex-mobile{display:flex!important}}@media screen and (min-width:769px),print{.is-flex-tablet{display:flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-flex-tablet-only{display:flex!important}}@media screen and (max-width:1023px){.is-flex-touch{display:flex!important}}@media screen and (min-width:1024px){.is-flex-desktop{display:flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-flex-desktop-only{display:flex!important}}@media screen and (min-width:1216px){.is-flex-widescreen{display:flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-flex-widescreen-only{display:flex!important}}@media screen and (min-width:1408px){.is-flex-fullhd{display:flex!important}}.is-inline{display:inline!important}@media screen and (max-width:768px){.is-inline-mobile{display:inline!important}}@media screen and (min-width:769px),print{.is-inline-tablet{display:inline!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-tablet-only{display:inline!important}}@media screen and (max-width:1023px){.is-inline-touch{display:inline!important}}@media screen and (min-width:1024px){.is-inline-desktop{display:inline!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-desktop-only{display:inline!important}}@media screen and (min-width:1216px){.is-inline-widescreen{display:inline!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-widescreen-only{display:inline!important}}@media screen and (min-width:1408px){.is-inline-fullhd{display:inline!important}}.is-inline-block{display:inline-block!important}@media screen and (max-width:768px){.is-inline-block-mobile{display:inline-block!important}}@media screen and (min-width:769px),print{.is-inline-block-tablet{display:inline-block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-block-tablet-only{display:inline-block!important}}@media screen and (max-width:1023px){.is-inline-block-touch{display:inline-block!important}}@media screen and (min-width:1024px){.is-inline-block-desktop{display:inline-block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-block-desktop-only{display:inline-block!important}}@media screen and (min-width:1216px){.is-inline-block-widescreen{display:inline-block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-block-widescreen-only{display:inline-block!important}}@media screen and (min-width:1408px){.is-inline-block-fullhd{display:inline-block!important}}.is-inline-flex{display:inline-flex!important}@media screen and (max-width:768px){.is-inline-flex-mobile{display:inline-flex!important}}@media screen and (min-width:769px),print{.is-inline-flex-tablet{display:inline-flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-flex-tablet-only{display:inline-flex!important}}@media screen and (max-width:1023px){.is-inline-flex-touch{display:inline-flex!important}}@media screen and (min-width:1024px){.is-inline-flex-desktop{display:inline-flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-flex-desktop-only{display:inline-flex!important}}@media screen and (min-width:1216px){.is-inline-flex-widescreen{display:inline-flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-flex-widescreen-only{display:inline-flex!important}}@media screen and (min-width:1408px){.is-inline-flex-fullhd{display:inline-flex!important}}.is-hidden{display:none!important}.is-sr-only{border:none!important;clip:rect(0,0,0,0)!important;height:.01em!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:.01em!important}@media screen and (max-width:768px){.is-hidden-mobile{display:none!important}}@media screen and (min-width:769px),print{.is-hidden-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-hidden-tablet-only{display:none!important}}@media screen and (max-width:1023px){.is-hidden-touch{display:none!important}}@media screen and (min-width:1024px){.is-hidden-desktop{display:none!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-hidden-desktop-only{display:none!important}}@media screen and (min-width:1216px){.is-hidden-widescreen{display:none!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-hidden-widescreen-only{display:none!important}}@media screen and (min-width:1408px){.is-hidden-fullhd{display:none!important}}.is-invisible{visibility:hidden!important}@media screen and (max-width:768px){.is-invisible-mobile{visibility:hidden!important}}@media screen and (min-width:769px),print{.is-invisible-tablet{visibility:hidden!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-invisible-tablet-only{visibility:hidden!important}}@media screen and (max-width:1023px){.is-invisible-touch{visibility:hidden!important}}@media screen and (min-width:1024px){.is-invisible-desktop{visibility:hidden!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-invisible-desktop-only{visibility:hidden!important}}@media screen and (min-width:1216px){.is-invisible-widescreen{visibility:hidden!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-invisible-widescreen-only{visibility:hidden!important}}@media screen and (min-width:1408px){.is-invisible-fullhd{visibility:hidden!important}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:0 0}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width:1023px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,.7)}.hero.is-white .navbar-link.is-active,.hero.is-white .navbar-link:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff!important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,.7)}.hero.is-black .navbar-link.is-active,.hero.is-black .navbar-link:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black a.navbar-item:hover{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a!important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}@media screen and (max-width:768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,.7)}.hero.is-light .subtitle{color:rgba(0,0,0,.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,.7)}.hero.is-light .navbar-link.is-active,.hero.is-light .navbar-link:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.hero.is-light .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5!important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}}.hero.is-dark{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#fff}.hero.is-dark .subtitle{color:rgba(255,255,255,.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(255,255,255,.7)}.hero.is-dark .navbar-link.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark a.navbar-item:hover{background-color:#292929;color:#fff}.hero.is-dark .tabs a{color:#fff;opacity:.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{color:#363636!important;opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}@media screen and (max-width:768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,.7)}.hero.is-primary .navbar-link.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary a.navbar-item:hover{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{color:#00d1b2!important;opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}@media screen and (max-width:768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}}.hero.is-link{background-color:#485fc7;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-link .navbar-menu{background-color:#485fc7}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,.7)}.hero.is-link .navbar-link.is-active,.hero.is-link .navbar-link:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link a.navbar-item:hover{background-color:#3a51bb;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#485fc7!important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#485fc7}.hero.is-link.is-bold{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}@media screen and (max-width:768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}}.hero.is-info{background-color:#3e8ed0;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-info .navbar-menu{background-color:#3e8ed0}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,.7)}.hero.is-info .navbar-link.is-active,.hero.is-info .navbar-link:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info a.navbar-item:hover{background-color:#3082c5;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#3e8ed0!important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3e8ed0}.hero.is-info.is-bold{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}@media screen and (max-width:768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}}.hero.is-success{background-color:#48c78e;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-success .navbar-menu{background-color:#48c78e}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,.7)}.hero.is-success .navbar-link.is-active,.hero.is-success .navbar-link:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success a.navbar-item:hover{background-color:#3abb81;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#48c78e!important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#48c78e}.hero.is-success.is-bold{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}@media screen and (max-width:768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}}.hero.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-warning .navbar-menu{background-color:#ffe08a}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,.7)}.hero.is-warning .navbar-link.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffe08a!important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#ffe08a}.hero.is-warning.is-bold{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}@media screen and (max-width:768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}}.hero.is-danger{background-color:#f14668;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-danger .navbar-menu{background-color:#f14668}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,.7)}.hero.is-danger .navbar-link.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger a.navbar-item:hover{background-color:#ef2e55;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#f14668!important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#f14668}.hero.is-danger.is-bold{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}@media screen and (max-width:768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}}.hero.is-small .hero-body{padding:1.5rem}@media screen and (min-width:769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width:769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body,.hero.is-halfheight .hero-body{align-items:center;display:flex}.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container,.hero.is-halfheight .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0)}.hero-video.is-transparent{opacity:.3}@media screen and (max-width:768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width:768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:.75rem}}@media screen and (min-width:769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-foot,.hero-head{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width:769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width:1024px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem} \ No newline at end of file diff --git a/templ/examples/counter-basic/assets/favicon/about.txt b/templ/examples/counter-basic/assets/favicon/about.txt new file mode 100644 index 0000000..7d6aedf --- /dev/null +++ b/templ/examples/counter-basic/assets/favicon/about.txt @@ -0,0 +1,6 @@ +This favicon was generated using the following font: + +- Font Title: Leckerli One +- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" +- Font Source: http://fonts.gstatic.com/s/leckerlione/v16/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf +- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL)) diff --git a/templ/examples/counter-basic/assets/favicon/android-chrome-192x192.png b/templ/examples/counter-basic/assets/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..e218b89 Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/android-chrome-192x192.png differ diff --git a/templ/examples/counter-basic/assets/favicon/android-chrome-512x512.png b/templ/examples/counter-basic/assets/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..f02fe55 Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/android-chrome-512x512.png differ diff --git a/templ/examples/counter-basic/assets/favicon/apple-touch-icon.png b/templ/examples/counter-basic/assets/favicon/apple-touch-icon.png new file mode 100644 index 0000000..1f51b01 Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/apple-touch-icon.png differ diff --git a/templ/examples/counter-basic/assets/favicon/favicon-16x16.png b/templ/examples/counter-basic/assets/favicon/favicon-16x16.png new file mode 100644 index 0000000..63b5d9e Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/favicon-16x16.png differ diff --git a/templ/examples/counter-basic/assets/favicon/favicon-32x32.png b/templ/examples/counter-basic/assets/favicon/favicon-32x32.png new file mode 100644 index 0000000..45de0e0 Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/favicon-32x32.png differ diff --git a/templ/examples/counter-basic/assets/favicon/favicon.ico b/templ/examples/counter-basic/assets/favicon/favicon.ico new file mode 100644 index 0000000..f29ddcc Binary files /dev/null and b/templ/examples/counter-basic/assets/favicon/favicon.ico differ diff --git a/templ/examples/counter-basic/assets/favicon/site.webmanifest b/templ/examples/counter-basic/assets/favicon/site.webmanifest new file mode 100644 index 0000000..67ed3d1 --- /dev/null +++ b/templ/examples/counter-basic/assets/favicon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/assets/favicon/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/assets/favicon/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} diff --git a/templ/examples/counter-basic/assets/logo.png b/templ/examples/counter-basic/assets/logo.png new file mode 100644 index 0000000..cf9411a Binary files /dev/null and b/templ/examples/counter-basic/assets/logo.png differ diff --git a/templ/examples/counter-basic/components.templ b/templ/examples/counter-basic/components.templ new file mode 100644 index 0000000..413f8ec --- /dev/null +++ b/templ/examples/counter-basic/components.templ @@ -0,0 +1,49 @@ +package main + +import "strconv" + +templ counts(global, user int) { +
Global: { strconv.Itoa(global) }
+
User: { strconv.Itoa(user) }
+} + +templ form() { +
+
+
+
+} + +templ page(global, user int) { + + + + + Counts + + + + + + + +
+
+
+

Counts

+
+
+
+
+
+
+
+ @counts(global, user) + @form() +
+
+
+
+ + +} diff --git a/templ/examples/counter-basic/components_templ.go b/templ/examples/counter-basic/components_templ.go new file mode 100644 index 0000000..8c36418 --- /dev/null +++ b/templ/examples/counter-basic/components_templ.go @@ -0,0 +1,138 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "strconv" + +func counts(global, user int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Global: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(global)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/counter-basic/components.templ`, Line: 6, Col: 36} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
User: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(user)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/counter-basic/components.templ`, Line: 7, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func form() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func page(global, user int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "Counts

Counts

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = counts(global, user).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = form().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/counter-basic/fly.toml b/templ/examples/counter-basic/fly.toml new file mode 100644 index 0000000..b89211c --- /dev/null +++ b/templ/examples/counter-basic/fly.toml @@ -0,0 +1,39 @@ +# fly.toml file generated for counter-basic on 2023-04-28T14:22:23+01:00 + +app = "counter-basic" +kill_signal = "SIGINT" +kill_timeout = 5 +primary_region = "lhr" +processes = [] + +[env] + PORT = "8080" + +[experimental] + auto_rollback = true + +[[services]] + http_checks = [] + internal_port = 8080 + processes = ["app"] + protocol = "tcp" + script_checks = [] + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + force_https = true + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 0 + timeout = "2s" diff --git a/templ/examples/counter-basic/go.mod b/templ/examples/counter-basic/go.mod new file mode 100644 index 0000000..6d20a60 --- /dev/null +++ b/templ/examples/counter-basic/go.mod @@ -0,0 +1,11 @@ +module github.com/a-h/templ/examples/counter-basic + +go 1.23 + +toolchain go1.23.3 + +require github.com/a-h/templ v0.2.233 + +require github.com/alexedwards/scs/v2 v2.8.0 + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/counter-basic/go.sum b/templ/examples/counter-basic/go.sum new file mode 100644 index 0000000..6112236 --- /dev/null +++ b/templ/examples/counter-basic/go.sum @@ -0,0 +1,4 @@ +github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw= +github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/counter-basic/main.go b/templ/examples/counter-basic/main.go new file mode 100644 index 0000000..6c10367 --- /dev/null +++ b/templ/examples/counter-basic/main.go @@ -0,0 +1,69 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "time" + + "github.com/alexedwards/scs/v2" +) + +type GlobalState struct { + Count int +} + +var global GlobalState +var sessionManager *scs.SessionManager + +func getHandler(w http.ResponseWriter, r *http.Request) { + userCount := sessionManager.GetInt(r.Context(), "count") + component := page(global.Count, userCount) + component.Render(r.Context(), w) +} + +func postHandler(w http.ResponseWriter, r *http.Request) { + // Update state. + r.ParseForm() + + // Check to see if the global button was pressed. + if r.Form.Has("global") { + global.Count++ + } + if r.Form.Has("user") { + currentCount := sessionManager.GetInt(r.Context(), "count") + sessionManager.Put(r.Context(), "count", currentCount+1) + } + + // Display the form. + getHandler(w, r) +} + +func main() { + // Initialize the session. + sessionManager = scs.New() + sessionManager.Lifetime = 24 * time.Hour + + mux := http.NewServeMux() + + // Handle POST and GET requests. + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + postHandler(w, r) + return + } + getHandler(w, r) + }) + + // Include the static content. + mux.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets")))) + + // Add the middleware. + muxWithSessionMiddleware := sessionManager.LoadAndSave(mux) + + // Start the server. + fmt.Println("listening on :8080") + if err := http.ListenAndServe("127.0.0.1:8080", muxWithSessionMiddleware); err != nil { + log.Printf("error listening: %v", err) + } +} diff --git a/templ/examples/counter/Dockerfile b/templ/examples/counter/Dockerfile new file mode 100644 index 0000000..af50ac9 --- /dev/null +++ b/templ/examples/counter/Dockerfile @@ -0,0 +1,3 @@ +FROM pierrezemb/gostatic +COPY ./public/ /srv/http/ +ENTRYPOINT ["/goStatic", "-port", "8080"] diff --git a/templ/examples/counter/README.md b/templ/examples/counter/README.md new file mode 100644 index 0000000..4228b90 --- /dev/null +++ b/templ/examples/counter/README.md @@ -0,0 +1,25 @@ +## Tasks + +### generate + +```sh +templ generate +``` + +### deploy + +requires: generate +dir: cdk + +```sh +cdk deploy +``` + +### deploy-hotswap + +requires: generate +dir: cdk + +```sh +cdk deploy --hotswap +``` diff --git a/templ/examples/counter/assets/css/bulma.css b/templ/examples/counter/assets/css/bulma.css new file mode 100644 index 0000000..1dbfc86 --- /dev/null +++ b/templ/examples/counter/assets/css/bulma.css @@ -0,0 +1,11851 @@ +/*! bulma.io v0.9.4 | MIT License | github.com/jgthms/bulma */ +/* Bulma Utilities */ +.button, .input, .textarea, .select select, .file-cta, +.file-name, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.5em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; +} + +.button:focus, .input:focus, .textarea:focus, .select select:focus, .file-cta:focus, +.file-name:focus, .pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus, +.pagination-ellipsis:focus, .is-focused.button, .is-focused.input, .is-focused.textarea, .select select.is-focused, .is-focused.file-cta, +.is-focused.file-name, .is-focused.pagination-previous, +.is-focused.pagination-next, +.is-focused.pagination-link, +.is-focused.pagination-ellipsis, .button:active, .input:active, .textarea:active, .select select:active, .file-cta:active, +.file-name:active, .pagination-previous:active, +.pagination-next:active, +.pagination-link:active, +.pagination-ellipsis:active, .is-active.button, .is-active.input, .is-active.textarea, .select select.is-active, .is-active.file-cta, +.is-active.file-name, .is-active.pagination-previous, +.is-active.pagination-next, +.is-active.pagination-link, +.is-active.pagination-ellipsis { + outline: none; +} + +.button[disabled], .input[disabled], .textarea[disabled], .select select[disabled], .file-cta[disabled], +.file-name[disabled], .pagination-previous[disabled], +.pagination-next[disabled], +.pagination-link[disabled], +.pagination-ellipsis[disabled], +fieldset[disabled] .button, +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +.select fieldset[disabled] select, +fieldset[disabled] .file-cta, +fieldset[disabled] .file-name, +fieldset[disabled] .pagination-previous, +fieldset[disabled] .pagination-next, +fieldset[disabled] .pagination-link, +fieldset[disabled] .pagination-ellipsis { + cursor: not-allowed; +} + +.button, .file, .breadcrumb, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .tabs, .is-unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; +} + +.box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .block:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .message:not(:last-child), .pagination:not(:last-child), .tabs:not(:last-child) { + margin-bottom: 1.5rem; +} + +.delete, .modal-close { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 9999px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; +} + +.delete::before, .modal-close::before, .delete::after, .modal-close::after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} + +.delete::before, .modal-close::before { + height: 2px; + width: 50%; +} + +.delete::after, .modal-close::after { + height: 50%; + width: 2px; +} + +.delete:hover, .modal-close:hover, .delete:focus, .modal-close:focus { + background-color: rgba(10, 10, 10, 0.3); +} + +.delete:active, .modal-close:active { + background-color: rgba(10, 10, 10, 0.4); +} + +.is-small.delete, .is-small.modal-close { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; +} + +.is-medium.delete, .is-medium.modal-close { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; +} + +.is-large.delete, .is-large.modal-close { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; +} + +.button.is-loading::after, .loader, .select.is-loading::after, .control.is-loading::after { + -webkit-animation: spinAround 500ms infinite linear; + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 9999px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} + +.image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio, .modal, .modal-background, .is-overlay, .hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.navbar-burger { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + color: currentColor; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; +} + +/* Bulma Base */ +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +ul { + list-style: none; +} + +button, +input, +select, +textarea { + margin: 0; +} + +html { + box-sizing: border-box; +} + +*, *::before, *::after { + box-sizing: inherit; +} + +img, +video { + height: auto; + max-width: 100%; +} + +iframe { + border: 0; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} + +td:not([align]), +th:not([align]) { + text-align: inherit; +} + +html { + background-color: white; + font-size: 16px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; +} + +body, +button, +input, +optgroup, +select, +textarea { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; +} + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: monospace; +} + +body { + color: #4a4a4a; + font-size: 1em; + font-weight: 400; + line-height: 1.5; +} + +a { + color: #485fc7; + cursor: pointer; + text-decoration: none; +} + +a strong { + color: currentColor; +} + +a:hover { + color: #363636; +} + +code { + background-color: whitesmoke; + color: #da1039; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; +} + +hr { + background-color: whitesmoke; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; +} + +img { + height: auto; + max-width: 100%; +} + +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; +} + +small { + font-size: 0.875em; +} + +span { + font-style: inherit; + font-weight: inherit; +} + +strong { + color: #363636; + font-weight: 700; +} + +fieldset { + border: none; +} + +pre { + -webkit-overflow-scrolling: touch; + background-color: whitesmoke; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; +} + +pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; +} + +table td, +table th { + vertical-align: top; +} + +table td:not([align]), +table th:not([align]) { + text-align: inherit; +} + +table th { + color: #363636; +} + +@-webkit-keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} + +@keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} + +/* Bulma Elements */ +.box { + background-color: white; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + display: block; + padding: 1.25rem; +} + +a.box:hover, a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px #485fc7; +} + +a.box:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2), 0 0 0 1px #485fc7; +} + +.button { + background-color: white; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.5em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.5em - 1px); + text-align: center; + white-space: nowrap; +} + +.button strong { + color: inherit; +} + +.button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; +} + +.button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; +} + +.button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); +} + +.button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); +} + +.button:hover, .button.is-hovered { + border-color: #b5b5b5; + color: #363636; +} + +.button:focus, .button.is-focused { + border-color: #485fc7; + color: #363636; +} + +.button:focus:not(:active), .button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.button:active, .button.is-active { + border-color: #4a4a4a; + color: #363636; +} + +.button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; +} + +.button.is-text:hover, .button.is-text.is-hovered, .button.is-text:focus, .button.is-text.is-focused { + background-color: whitesmoke; + color: #363636; +} + +.button.is-text:active, .button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; +} + +.button.is-text[disabled], +fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} + +.button.is-ghost { + background: none; + border-color: transparent; + color: #485fc7; + text-decoration: none; +} + +.button.is-ghost:hover, .button.is-ghost.is-hovered { + color: #485fc7; + text-decoration: underline; +} + +.button.is-white { + background-color: white; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:hover, .button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:focus, .button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.button.is-white:active, .button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} + +.button.is-white[disabled], +fieldset[disabled] .button.is-white { + background-color: white; + border-color: white; + box-shadow: none; +} + +.button.is-white.is-inverted { + background-color: #0a0a0a; + color: white; +} + +.button.is-white.is-inverted:hover, .button.is-white.is-inverted.is-hovered { + background-color: black; +} + +.button.is-white.is-inverted[disabled], +fieldset[disabled] .button.is-white.is-inverted { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: white; +} + +.button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-white.is-outlined { + background-color: transparent; + border-color: white; + color: white; +} + +.button.is-white.is-outlined:hover, .button.is-white.is-outlined.is-hovered, .button.is-white.is-outlined:focus, .button.is-white.is-outlined.is-focused { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent white white !important; +} + +.button.is-white.is-outlined.is-loading:hover::after, .button.is-white.is-outlined.is-loading.is-hovered::after, .button.is-white.is-outlined.is-loading:focus::after, .button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-white.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; +} + +.button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} + +.button.is-white.is-inverted.is-outlined:hover, .button.is-white.is-inverted.is-outlined.is-hovered, .button.is-white.is-inverted.is-outlined:focus, .button.is-white.is-inverted.is-outlined.is-focused { + background-color: #0a0a0a; + color: white; +} + +.button.is-white.is-inverted.is-outlined.is-loading:hover::after, .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-white.is-inverted.is-outlined.is-loading:focus::after, .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; +} + +.button.is-white.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: white; +} + +.button.is-black:hover, .button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: white; +} + +.button.is-black:focus, .button.is-black.is-focused { + border-color: transparent; + color: white; +} + +.button.is-black:focus:not(:active), .button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.button.is-black:active, .button.is-black.is-active { + background-color: black; + border-color: transparent; + color: white; +} + +.button.is-black[disabled], +fieldset[disabled] .button.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + box-shadow: none; +} + +.button.is-black.is-inverted { + background-color: white; + color: #0a0a0a; +} + +.button.is-black.is-inverted:hover, .button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-black.is-inverted[disabled], +fieldset[disabled] .button.is-black.is-inverted { + background-color: white; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black.is-loading::after { + border-color: transparent transparent white white !important; +} + +.button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; +} + +.button.is-black.is-outlined:hover, .button.is-black.is-outlined.is-hovered, .button.is-black.is-outlined:focus, .button.is-black.is-outlined.is-focused { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-black.is-outlined.is-loading:hover::after, .button.is-black.is-outlined.is-loading.is-hovered::after, .button.is-black.is-outlined.is-loading:focus::after, .button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; +} + +.button.is-black.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; +} + +.button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + color: white; +} + +.button.is-black.is-inverted.is-outlined:hover, .button.is-black.is-inverted.is-outlined.is-hovered, .button.is-black.is-inverted.is-outlined:focus, .button.is-black.is-inverted.is-outlined.is-focused { + background-color: white; + color: #0a0a0a; +} + +.button.is-black.is-inverted.is-outlined.is-loading:hover::after, .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-black.is-inverted.is-outlined.is-loading:focus::after, .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; +} + +.button.is-black.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; +} + +.button.is-light { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:hover, .button.is-light.is-hovered { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:focus, .button.is-light.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light:focus:not(:active), .button.is-light.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.button.is-light:active, .button.is-light.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light[disabled], +fieldset[disabled] .button.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; +} + +.button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.button.is-light.is-inverted:hover, .button.is-light.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-inverted[disabled], +fieldset[disabled] .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: whitesmoke; +} + +.button.is-light.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; +} + +.button.is-light.is-outlined:hover, .button.is-light.is-outlined.is-hovered, .button.is-light.is-outlined:focus, .button.is-light.is-outlined.is-focused { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-outlined.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; +} + +.button.is-light.is-outlined.is-loading:hover::after, .button.is-light.is-outlined.is-loading.is-hovered::after, .button.is-light.is-outlined.is-loading:focus::after, .button.is-light.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-light.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; +} + +.button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); +} + +.button.is-light.is-inverted.is-outlined:hover, .button.is-light.is-inverted.is-outlined.is-hovered, .button.is-light.is-inverted.is-outlined:focus, .button.is-light.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.button.is-light.is-inverted.is-outlined.is-loading:hover::after, .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-light.is-inverted.is-outlined.is-loading:focus::after, .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent whitesmoke whitesmoke !important; +} + +.button.is-light.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; +} + +.button.is-dark:hover, .button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} + +.button.is-dark:focus, .button.is-dark.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-dark:focus:not(:active), .button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.button.is-dark:active, .button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; +} + +.button.is-dark[disabled], +fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: #363636; + box-shadow: none; +} + +.button.is-dark.is-inverted { + background-color: #fff; + color: #363636; +} + +.button.is-dark.is-inverted:hover, .button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-dark.is-inverted[disabled], +fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; +} + +.button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; +} + +.button.is-dark.is-outlined:hover, .button.is-dark.is-outlined.is-hovered, .button.is-dark.is-outlined:focus, .button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; +} + +.button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; +} + +.button.is-dark.is-outlined.is-loading:hover::after, .button.is-dark.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-outlined.is-loading:focus::after, .button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-dark.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; +} + +.button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-dark.is-inverted.is-outlined:hover, .button.is-dark.is-inverted.is-outlined.is-hovered, .button.is-dark.is-inverted.is-outlined:focus, .button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; +} + +.button.is-dark.is-inverted.is-outlined.is-loading:hover::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-inverted.is-outlined.is-loading:focus::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; +} + +.button.is-dark.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-primary { + background-color: #00d1b2; + border-color: transparent; + color: #fff; +} + +.button.is-primary:hover, .button.is-primary.is-hovered { + background-color: #00c4a7; + border-color: transparent; + color: #fff; +} + +.button.is-primary:focus, .button.is-primary.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-primary:focus:not(:active), .button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.button.is-primary:active, .button.is-primary.is-active { + background-color: #00b89c; + border-color: transparent; + color: #fff; +} + +.button.is-primary[disabled], +fieldset[disabled] .button.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + box-shadow: none; +} + +.button.is-primary.is-inverted { + background-color: #fff; + color: #00d1b2; +} + +.button.is-primary.is-inverted:hover, .button.is-primary.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-primary.is-inverted[disabled], +fieldset[disabled] .button.is-primary.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #00d1b2; +} + +.button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + color: #00d1b2; +} + +.button.is-primary.is-outlined:hover, .button.is-primary.is-outlined.is-hovered, .button.is-primary.is-outlined:focus, .button.is-primary.is-outlined.is-focused { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; +} + +.button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; +} + +.button.is-primary.is-outlined.is-loading:hover::after, .button.is-primary.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-outlined.is-loading:focus::after, .button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-primary.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + box-shadow: none; + color: #00d1b2; +} + +.button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-primary.is-inverted.is-outlined:hover, .button.is-primary.is-inverted.is-outlined.is-hovered, .button.is-primary.is-inverted.is-outlined:focus, .button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #00d1b2; +} + +.button.is-primary.is-inverted.is-outlined.is-loading:hover::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-inverted.is-outlined.is-loading:focus::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; +} + +.button.is-primary.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.button.is-primary.is-light:hover, .button.is-primary.is-light.is-hovered { + background-color: #defffa; + border-color: transparent; + color: #00947e; +} + +.button.is-primary.is-light:active, .button.is-primary.is-light.is-active { + background-color: #d1fff8; + border-color: transparent; + color: #00947e; +} + +.button.is-link { + background-color: #485fc7; + border-color: transparent; + color: #fff; +} + +.button.is-link:hover, .button.is-link.is-hovered { + background-color: #3e56c4; + border-color: transparent; + color: #fff; +} + +.button.is-link:focus, .button.is-link.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-link:focus:not(:active), .button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.button.is-link:active, .button.is-link.is-active { + background-color: #3a51bb; + border-color: transparent; + color: #fff; +} + +.button.is-link[disabled], +fieldset[disabled] .button.is-link { + background-color: #485fc7; + border-color: #485fc7; + box-shadow: none; +} + +.button.is-link.is-inverted { + background-color: #fff; + color: #485fc7; +} + +.button.is-link.is-inverted:hover, .button.is-link.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-link.is-inverted[disabled], +fieldset[disabled] .button.is-link.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #485fc7; +} + +.button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-link.is-outlined { + background-color: transparent; + border-color: #485fc7; + color: #485fc7; +} + +.button.is-link.is-outlined:hover, .button.is-link.is-outlined.is-hovered, .button.is-link.is-outlined:focus, .button.is-link.is-outlined.is-focused { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #485fc7 #485fc7 !important; +} + +.button.is-link.is-outlined.is-loading:hover::after, .button.is-link.is-outlined.is-loading.is-hovered::after, .button.is-link.is-outlined.is-loading:focus::after, .button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-link.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #485fc7; + box-shadow: none; + color: #485fc7; +} + +.button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-link.is-inverted.is-outlined:hover, .button.is-link.is-inverted.is-outlined.is-hovered, .button.is-link.is-inverted.is-outlined:focus, .button.is-link.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #485fc7; +} + +.button.is-link.is-inverted.is-outlined.is-loading:hover::after, .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-link.is-inverted.is-outlined.is-loading:focus::after, .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #485fc7 #485fc7 !important; +} + +.button.is-link.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.button.is-link.is-light:hover, .button.is-link.is-light.is-hovered { + background-color: #e6e9f7; + border-color: transparent; + color: #3850b7; +} + +.button.is-link.is-light:active, .button.is-link.is-light.is-active { + background-color: #dce0f4; + border-color: transparent; + color: #3850b7; +} + +.button.is-info { + background-color: #3e8ed0; + border-color: transparent; + color: #fff; +} + +.button.is-info:hover, .button.is-info.is-hovered { + background-color: #3488ce; + border-color: transparent; + color: #fff; +} + +.button.is-info:focus, .button.is-info.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-info:focus:not(:active), .button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.button.is-info:active, .button.is-info.is-active { + background-color: #3082c5; + border-color: transparent; + color: #fff; +} + +.button.is-info[disabled], +fieldset[disabled] .button.is-info { + background-color: #3e8ed0; + border-color: #3e8ed0; + box-shadow: none; +} + +.button.is-info.is-inverted { + background-color: #fff; + color: #3e8ed0; +} + +.button.is-info.is-inverted:hover, .button.is-info.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-info.is-inverted[disabled], +fieldset[disabled] .button.is-info.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3e8ed0; +} + +.button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-info.is-outlined { + background-color: transparent; + border-color: #3e8ed0; + color: #3e8ed0; +} + +.button.is-info.is-outlined:hover, .button.is-info.is-outlined.is-hovered, .button.is-info.is-outlined:focus, .button.is-info.is-outlined.is-focused { + background-color: #3e8ed0; + border-color: #3e8ed0; + color: #fff; +} + +.button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #3e8ed0 #3e8ed0 !important; +} + +.button.is-info.is-outlined.is-loading:hover::after, .button.is-info.is-outlined.is-loading.is-hovered::after, .button.is-info.is-outlined.is-loading:focus::after, .button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-info.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #3e8ed0; + box-shadow: none; + color: #3e8ed0; +} + +.button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-info.is-inverted.is-outlined:hover, .button.is-info.is-inverted.is-outlined.is-hovered, .button.is-info.is-inverted.is-outlined:focus, .button.is-info.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3e8ed0; +} + +.button.is-info.is-inverted.is-outlined.is-loading:hover::after, .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-info.is-inverted.is-outlined.is-loading:focus::after, .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3e8ed0 #3e8ed0 !important; +} + +.button.is-info.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.button.is-info.is-light:hover, .button.is-info.is-light.is-hovered { + background-color: #e4eff9; + border-color: transparent; + color: #296fa8; +} + +.button.is-info.is-light:active, .button.is-info.is-light.is-active { + background-color: #dae9f6; + border-color: transparent; + color: #296fa8; +} + +.button.is-success { + background-color: #48c78e; + border-color: transparent; + color: #fff; +} + +.button.is-success:hover, .button.is-success.is-hovered { + background-color: #3ec487; + border-color: transparent; + color: #fff; +} + +.button.is-success:focus, .button.is-success.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-success:focus:not(:active), .button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.button.is-success:active, .button.is-success.is-active { + background-color: #3abb81; + border-color: transparent; + color: #fff; +} + +.button.is-success[disabled], +fieldset[disabled] .button.is-success { + background-color: #48c78e; + border-color: #48c78e; + box-shadow: none; +} + +.button.is-success.is-inverted { + background-color: #fff; + color: #48c78e; +} + +.button.is-success.is-inverted:hover, .button.is-success.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-success.is-inverted[disabled], +fieldset[disabled] .button.is-success.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #48c78e; +} + +.button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-success.is-outlined { + background-color: transparent; + border-color: #48c78e; + color: #48c78e; +} + +.button.is-success.is-outlined:hover, .button.is-success.is-outlined.is-hovered, .button.is-success.is-outlined:focus, .button.is-success.is-outlined.is-focused { + background-color: #48c78e; + border-color: #48c78e; + color: #fff; +} + +.button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #48c78e #48c78e !important; +} + +.button.is-success.is-outlined.is-loading:hover::after, .button.is-success.is-outlined.is-loading.is-hovered::after, .button.is-success.is-outlined.is-loading:focus::after, .button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-success.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c78e; + box-shadow: none; + color: #48c78e; +} + +.button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-success.is-inverted.is-outlined:hover, .button.is-success.is-inverted.is-outlined.is-hovered, .button.is-success.is-inverted.is-outlined:focus, .button.is-success.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #48c78e; +} + +.button.is-success.is-inverted.is-outlined.is-loading:hover::after, .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-success.is-inverted.is-outlined.is-loading:focus::after, .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #48c78e #48c78e !important; +} + +.button.is-success.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.button.is-success.is-light:hover, .button.is-success.is-light.is-hovered { + background-color: #e6f7ef; + border-color: transparent; + color: #257953; +} + +.button.is-success.is-light:active, .button.is-success.is-light.is-active { + background-color: #dcf4e9; + border-color: transparent; + color: #257953; +} + +.button.is-warning { + background-color: #ffe08a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:hover, .button.is-warning.is-hovered { + background-color: #ffdc7d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:focus, .button.is-warning.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning:focus:not(:active), .button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.button.is-warning:active, .button.is-warning.is-active { + background-color: #ffd970; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning[disabled], +fieldset[disabled] .button.is-warning { + background-color: #ffe08a; + border-color: #ffe08a; + box-shadow: none; +} + +.button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.button.is-warning.is-inverted:hover, .button.is-warning.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-inverted[disabled], +fieldset[disabled] .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: #ffe08a; +} + +.button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffe08a; + color: #ffe08a; +} + +.button.is-warning.is-outlined:hover, .button.is-warning.is-outlined.is-hovered, .button.is-warning.is-outlined:focus, .button.is-warning.is-outlined.is-focused { + background-color: #ffe08a; + border-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffe08a #ffe08a !important; +} + +.button.is-warning.is-outlined.is-loading:hover::after, .button.is-warning.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-outlined.is-loading:focus::after, .button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; +} + +.button.is-warning.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffe08a; + box-shadow: none; + color: #ffe08a; +} + +.button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-inverted.is-outlined:hover, .button.is-warning.is-inverted.is-outlined.is-hovered, .button.is-warning.is-inverted.is-outlined:focus, .button.is-warning.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.button.is-warning.is-inverted.is-outlined.is-loading:hover::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-inverted.is-outlined.is-loading:focus::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ffe08a #ffe08a !important; +} + +.button.is-warning.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); +} + +.button.is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.button.is-warning.is-light:hover, .button.is-warning.is-light.is-hovered { + background-color: #fff6de; + border-color: transparent; + color: #946c00; +} + +.button.is-warning.is-light:active, .button.is-warning.is-light.is-active { + background-color: #fff3d1; + border-color: transparent; + color: #946c00; +} + +.button.is-danger { + background-color: #f14668; + border-color: transparent; + color: #fff; +} + +.button.is-danger:hover, .button.is-danger.is-hovered { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} + +.button.is-danger:focus, .button.is-danger.is-focused { + border-color: transparent; + color: #fff; +} + +.button.is-danger:focus:not(:active), .button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.button.is-danger:active, .button.is-danger.is-active { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} + +.button.is-danger[disabled], +fieldset[disabled] .button.is-danger { + background-color: #f14668; + border-color: #f14668; + box-shadow: none; +} + +.button.is-danger.is-inverted { + background-color: #fff; + color: #f14668; +} + +.button.is-danger.is-inverted:hover, .button.is-danger.is-inverted.is-hovered { + background-color: #f2f2f2; +} + +.button.is-danger.is-inverted[disabled], +fieldset[disabled] .button.is-danger.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #f14668; +} + +.button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + color: #f14668; +} + +.button.is-danger.is-outlined:hover, .button.is-danger.is-outlined.is-hovered, .button.is-danger.is-outlined:focus, .button.is-danger.is-outlined.is-focused { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} + +.button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #f14668 #f14668 !important; +} + +.button.is-danger.is-outlined.is-loading:hover::after, .button.is-danger.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-outlined.is-loading:focus::after, .button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; +} + +.button.is-danger.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + box-shadow: none; + color: #f14668; +} + +.button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; +} + +.button.is-danger.is-inverted.is-outlined:hover, .button.is-danger.is-inverted.is-outlined.is-hovered, .button.is-danger.is-inverted.is-outlined:focus, .button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #f14668; +} + +.button.is-danger.is-inverted.is-outlined.is-loading:hover::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-inverted.is-outlined.is-loading:focus::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f14668 #f14668 !important; +} + +.button.is-danger.is-inverted.is-outlined[disabled], +fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; +} + +.button.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.button.is-danger.is-light:hover, .button.is-danger.is-light.is-hovered { + background-color: #fde0e6; + border-color: transparent; + color: #cc0f35; +} + +.button.is-danger.is-light:active, .button.is-danger.is-light.is-active { + background-color: #fcd4dc; + border-color: transparent; + color: #cc0f35; +} + +.button.is-small { + font-size: 0.75rem; +} + +.button.is-small:not(.is-rounded) { + border-radius: 2px; +} + +.button.is-normal { + font-size: 1rem; +} + +.button.is-medium { + font-size: 1.25rem; +} + +.button.is-large { + font-size: 1.5rem; +} + +.button[disabled], +fieldset[disabled] .button { + background-color: white; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; +} + +.button.is-fullwidth { + display: flex; + width: 100%; +} + +.button.is-loading { + color: transparent !important; + pointer-events: none; +} + +.button.is-loading::after { + position: absolute; + left: calc(50% - (1em * 0.5)); + top: calc(50% - (1em * 0.5)); + position: absolute !important; +} + +.button.is-static { + background-color: whitesmoke; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; +} + +.button.is-rounded { + border-radius: 9999px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); +} + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.buttons .button { + margin-bottom: 0.5rem; +} + +.buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; +} + +.buttons:last-child { + margin-bottom: -0.5rem; +} + +.buttons:not(:last-child) { + margin-bottom: 1rem; +} + +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + font-size: 0.75rem; +} + +.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded) { + border-radius: 2px; +} + +.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; +} + +.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; +} + +.buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; +} + +.buttons.has-addons .button:last-child { + margin-right: 0; +} + +.buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; +} + +.buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; +} + +.buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; +} + +.buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.buttons.is-centered { + justify-content: center; +} + +.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} + +.buttons.is-right { + justify-content: flex-end; +} + +.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; +} + +@media screen and (max-width: 768px) { + .button.is-responsive.is-small { + font-size: 0.5625rem; + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: 0.65625rem; + } + .button.is-responsive.is-medium { + font-size: 0.75rem; + } + .button.is-responsive.is-large { + font-size: 1rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .button.is-responsive.is-small { + font-size: 0.65625rem; + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: 0.75rem; + } + .button.is-responsive.is-medium { + font-size: 1rem; + } + .button.is-responsive.is-large { + font-size: 1.25rem; + } +} + +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; +} + +.container.is-fluid { + max-width: none !important; + padding-left: 32px; + padding-right: 32px; + width: 100%; +} + +@media screen and (min-width: 1024px) { + .container { + max-width: 960px; + } +} + +@media screen and (max-width: 1215px) { + .container.is-widescreen:not(.is-max-desktop) { + max-width: 1152px; + } +} + +@media screen and (max-width: 1407px) { + .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} + +@media screen and (min-width: 1216px) { + .container:not(.is-max-desktop) { + max-width: 1152px; + } +} + +@media screen and (min-width: 1408px) { + .container:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} + +.content li + li { + margin-top: 0.25em; +} + +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; +} + +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 600; + line-height: 1.125; +} + +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; +} + +.content h1:not(:first-child) { + margin-top: 1em; +} + +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; +} + +.content h2:not(:first-child) { + margin-top: 1.1428em; +} + +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; +} + +.content h3:not(:first-child) { + margin-top: 1.3333em; +} + +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; +} + +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; +} + +.content h6 { + font-size: 1em; + margin-bottom: 1em; +} + +.content blockquote { + background-color: whitesmoke; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; +} + +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; +} + +.content ol:not([type]) { + list-style-type: decimal; +} + +.content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; +} + +.content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; +} + +.content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; +} + +.content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; +} + +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; +} + +.content ul ul { + list-style-type: circle; + margin-top: 0.5em; +} + +.content ul ul ul { + list-style-type: square; +} + +.content dd { + margin-left: 2em; +} + +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; +} + +.content figure:not(:first-child) { + margin-top: 2em; +} + +.content figure:not(:last-child) { + margin-bottom: 2em; +} + +.content figure img { + display: inline-block; +} + +.content figure figcaption { + font-style: italic; +} + +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; +} + +.content sup, +.content sub { + font-size: 75%; +} + +.content table { + width: 100%; +} + +.content table td, +.content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.content table th { + color: #363636; +} + +.content table th:not([align]) { + text-align: inherit; +} + +.content table thead td, +.content table thead th { + border-width: 0 0 2px; + color: #363636; +} + +.content table tfoot td, +.content table tfoot th { + border-width: 2px 0 0; + color: #363636; +} + +.content table tbody tr:last-child td, +.content table tbody tr:last-child th { + border-bottom-width: 0; +} + +.content .tabs li + li { + margin-top: 0; +} + +.content.is-small { + font-size: 0.75rem; +} + +.content.is-normal { + font-size: 1rem; +} + +.content.is-medium { + font-size: 1.25rem; +} + +.content.is-large { + font-size: 1.5rem; +} + +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; +} + +.icon.is-small { + height: 1rem; + width: 1rem; +} + +.icon.is-medium { + height: 2rem; + width: 2rem; +} + +.icon.is-large { + height: 3rem; + width: 3rem; +} + +.icon-text { + align-items: flex-start; + color: inherit; + display: inline-flex; + flex-wrap: wrap; + line-height: 1.5rem; + vertical-align: top; +} + +.icon-text .icon { + flex-grow: 0; + flex-shrink: 0; +} + +.icon-text .icon:not(:last-child) { + margin-right: 0.25em; +} + +.icon-text .icon:not(:first-child) { + margin-left: 0.25em; +} + +div.icon-text { + display: flex; +} + +.image { + display: block; + position: relative; +} + +.image img { + display: block; + height: auto; + width: 100%; +} + +.image img.is-rounded { + border-radius: 9999px; +} + +.image.is-fullwidth { + width: 100%; +} + +.image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio { + height: 100%; + width: 100%; +} + +.image.is-square, .image.is-1by1 { + padding-top: 100%; +} + +.image.is-5by4 { + padding-top: 80%; +} + +.image.is-4by3 { + padding-top: 75%; +} + +.image.is-3by2 { + padding-top: 66.6666%; +} + +.image.is-5by3 { + padding-top: 60%; +} + +.image.is-16by9 { + padding-top: 56.25%; +} + +.image.is-2by1 { + padding-top: 50%; +} + +.image.is-3by1 { + padding-top: 33.3333%; +} + +.image.is-4by5 { + padding-top: 125%; +} + +.image.is-3by4 { + padding-top: 133.3333%; +} + +.image.is-2by3 { + padding-top: 150%; +} + +.image.is-3by5 { + padding-top: 166.6666%; +} + +.image.is-9by16 { + padding-top: 177.7777%; +} + +.image.is-1by2 { + padding-top: 200%; +} + +.image.is-1by3 { + padding-top: 300%; +} + +.image.is-16x16 { + height: 16px; + width: 16px; +} + +.image.is-24x24 { + height: 24px; + width: 24px; +} + +.image.is-32x32 { + height: 32px; + width: 32px; +} + +.image.is-48x48 { + height: 48px; + width: 48px; +} + +.image.is-64x64 { + height: 64px; + width: 64px; +} + +.image.is-96x96 { + height: 96px; + width: 96px; +} + +.image.is-128x128 { + height: 128px; + width: 128px; +} + +.notification { + background-color: whitesmoke; + border-radius: 4px; + position: relative; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; +} + +.notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} + +.notification strong { + color: currentColor; +} + +.notification code, +.notification pre { + background: white; +} + +.notification pre code { + background: transparent; +} + +.notification > .delete { + right: 0.5rem; + position: absolute; + top: 0.5rem; +} + +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} + +.notification.is-white { + background-color: white; + color: #0a0a0a; +} + +.notification.is-black { + background-color: #0a0a0a; + color: white; +} + +.notification.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.notification.is-dark { + background-color: #363636; + color: #fff; +} + +.notification.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.notification.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.notification.is-link { + background-color: #485fc7; + color: #fff; +} + +.notification.is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.notification.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.notification.is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.notification.is-success { + background-color: #48c78e; + color: #fff; +} + +.notification.is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.notification.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.notification.is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.notification.is-danger { + background-color: #f14668; + color: #fff; +} + +.notification.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 9999px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; +} + +.progress::-webkit-progress-bar { + background-color: #ededed; +} + +.progress::-webkit-progress-value { + background-color: #4a4a4a; +} + +.progress::-moz-progress-bar { + background-color: #4a4a4a; +} + +.progress::-ms-fill { + background-color: #4a4a4a; + border: none; +} + +.progress.is-white::-webkit-progress-value { + background-color: white; +} + +.progress.is-white::-moz-progress-bar { + background-color: white; +} + +.progress.is-white::-ms-fill { + background-color: white; +} + +.progress.is-white:indeterminate { + background-image: linear-gradient(to right, white 30%, #ededed 30%); +} + +.progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; +} + +.progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; +} + +.progress.is-black::-ms-fill { + background-color: #0a0a0a; +} + +.progress.is-black:indeterminate { + background-image: linear-gradient(to right, #0a0a0a 30%, #ededed 30%); +} + +.progress.is-light::-webkit-progress-value { + background-color: whitesmoke; +} + +.progress.is-light::-moz-progress-bar { + background-color: whitesmoke; +} + +.progress.is-light::-ms-fill { + background-color: whitesmoke; +} + +.progress.is-light:indeterminate { + background-image: linear-gradient(to right, whitesmoke 30%, #ededed 30%); +} + +.progress.is-dark::-webkit-progress-value { + background-color: #363636; +} + +.progress.is-dark::-moz-progress-bar { + background-color: #363636; +} + +.progress.is-dark::-ms-fill { + background-color: #363636; +} + +.progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); +} + +.progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; +} + +.progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; +} + +.progress.is-primary::-ms-fill { + background-color: #00d1b2; +} + +.progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #00d1b2 30%, #ededed 30%); +} + +.progress.is-link::-webkit-progress-value { + background-color: #485fc7; +} + +.progress.is-link::-moz-progress-bar { + background-color: #485fc7; +} + +.progress.is-link::-ms-fill { + background-color: #485fc7; +} + +.progress.is-link:indeterminate { + background-image: linear-gradient(to right, #485fc7 30%, #ededed 30%); +} + +.progress.is-info::-webkit-progress-value { + background-color: #3e8ed0; +} + +.progress.is-info::-moz-progress-bar { + background-color: #3e8ed0; +} + +.progress.is-info::-ms-fill { + background-color: #3e8ed0; +} + +.progress.is-info:indeterminate { + background-image: linear-gradient(to right, #3e8ed0 30%, #ededed 30%); +} + +.progress.is-success::-webkit-progress-value { + background-color: #48c78e; +} + +.progress.is-success::-moz-progress-bar { + background-color: #48c78e; +} + +.progress.is-success::-ms-fill { + background-color: #48c78e; +} + +.progress.is-success:indeterminate { + background-image: linear-gradient(to right, #48c78e 30%, #ededed 30%); +} + +.progress.is-warning::-webkit-progress-value { + background-color: #ffe08a; +} + +.progress.is-warning::-moz-progress-bar { + background-color: #ffe08a; +} + +.progress.is-warning::-ms-fill { + background-color: #ffe08a; +} + +.progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ffe08a 30%, #ededed 30%); +} + +.progress.is-danger::-webkit-progress-value { + background-color: #f14668; +} + +.progress.is-danger::-moz-progress-bar { + background-color: #f14668; +} + +.progress.is-danger::-ms-fill { + background-color: #f14668; +} + +.progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #f14668 30%, #ededed 30%); +} + +.progress:indeterminate { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-name: moveIndeterminate; + animation-name: moveIndeterminate; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #4a4a4a 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; +} + +.progress:indeterminate::-webkit-progress-bar { + background-color: transparent; +} + +.progress:indeterminate::-moz-progress-bar { + background-color: transparent; +} + +.progress:indeterminate::-ms-fill { + animation-name: none; +} + +.progress.is-small { + height: 0.75rem; +} + +.progress.is-medium { + height: 1.25rem; +} + +.progress.is-large { + height: 1.5rem; +} + +@-webkit-keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} + +@keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} + +.table { + background-color: white; + color: #363636; +} + +.table td, +.table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; +} + +.table td.is-white, +.table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.table td.is-black, +.table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.table td.is-light, +.table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.table td.is-dark, +.table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; +} + +.table td.is-primary, +.table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; +} + +.table td.is-link, +.table th.is-link { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.table td.is-info, +.table th.is-info { + background-color: #3e8ed0; + border-color: #3e8ed0; + color: #fff; +} + +.table td.is-success, +.table th.is-success { + background-color: #48c78e; + border-color: #48c78e; + color: #fff; +} + +.table td.is-warning, +.table th.is-warning { + background-color: #ffe08a; + border-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.table td.is-danger, +.table th.is-danger { + background-color: #f14668; + border-color: #f14668; + color: #fff; +} + +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} + +.table td.is-selected, +.table th.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table td.is-selected a, +.table td.is-selected strong, +.table th.is-selected a, +.table th.is-selected strong { + color: currentColor; +} + +.table td.is-vcentered, +.table th.is-vcentered { + vertical-align: middle; +} + +.table th { + color: #363636; +} + +.table th:not([align]) { + text-align: left; +} + +.table tr.is-selected { + background-color: #00d1b2; + color: #fff; +} + +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} + +.table tr.is-selected td, +.table tr.is-selected th { + border-color: #fff; + color: currentColor; +} + +.table thead { + background-color: transparent; +} + +.table thead td, +.table thead th { + border-width: 0 0 2px; + color: #363636; +} + +.table tfoot { + background-color: transparent; +} + +.table tfoot td, +.table tfoot th { + border-width: 2px 0 0; + color: #363636; +} + +.table tbody { + background-color: transparent; +} + +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} + +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} + +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} + +.table.is-fullwidth { + width: 100%; +} + +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} + +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #fafafa; +} + +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: whitesmoke; +} + +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} + +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; +} + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} + +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.tags .tag { + margin-bottom: 0.5rem; +} + +.tags .tag:not(:last-child) { + margin-right: 0.5rem; +} + +.tags:last-child { + margin-bottom: -0.5rem; +} + +.tags:not(:last-child) { + margin-bottom: 1rem; +} + +.tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; +} + +.tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; +} + +.tags.is-centered { + justify-content: center; +} + +.tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; +} + +.tags.is-right { + justify-content: flex-end; +} + +.tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; +} + +.tags.is-right .tag:not(:last-child) { + margin-right: 0; +} + +.tags.has-addons .tag { + margin-right: 0; +} + +.tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.tags.has-addons .tag:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.tag:not(body) { + align-items: center; + background-color: whitesmoke; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; +} + +.tag:not(body).is-white { + background-color: white; + color: #0a0a0a; +} + +.tag:not(body).is-black { + background-color: #0a0a0a; + color: white; +} + +.tag:not(body).is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.tag:not(body).is-dark { + background-color: #363636; + color: #fff; +} + +.tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; +} + +.tag:not(body).is-primary.is-light { + background-color: #ebfffc; + color: #00947e; +} + +.tag:not(body).is-link { + background-color: #485fc7; + color: #fff; +} + +.tag:not(body).is-link.is-light { + background-color: #eff1fa; + color: #3850b7; +} + +.tag:not(body).is-info { + background-color: #3e8ed0; + color: #fff; +} + +.tag:not(body).is-info.is-light { + background-color: #eff5fb; + color: #296fa8; +} + +.tag:not(body).is-success { + background-color: #48c78e; + color: #fff; +} + +.tag:not(body).is-success.is-light { + background-color: #effaf5; + color: #257953; +} + +.tag:not(body).is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.tag:not(body).is-warning.is-light { + background-color: #fffaeb; + color: #946c00; +} + +.tag:not(body).is-danger { + background-color: #f14668; + color: #fff; +} + +.tag:not(body).is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; +} + +.tag:not(body).is-normal { + font-size: 0.75rem; +} + +.tag:not(body).is-medium { + font-size: 1rem; +} + +.tag:not(body).is-large { + font-size: 1.25rem; +} + +.tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; +} + +.tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; +} + +.tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; +} + +.tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; +} + +.tag:not(body).is-delete::before, .tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} + +.tag:not(body).is-delete::before { + height: 1px; + width: 50%; +} + +.tag:not(body).is-delete::after { + height: 50%; + width: 1px; +} + +.tag:not(body).is-delete:hover, .tag:not(body).is-delete:focus { + background-color: #e8e8e8; +} + +.tag:not(body).is-delete:active { + background-color: #dbdbdb; +} + +.tag:not(body).is-rounded { + border-radius: 9999px; +} + +a.tag:hover { + text-decoration: underline; +} + +.title, +.subtitle { + word-break: break-word; +} + +.title em, +.title span, +.subtitle em, +.subtitle span { + font-weight: inherit; +} + +.title sub, +.subtitle sub { + font-size: 0.75em; +} + +.title sup, +.subtitle sup { + font-size: 0.75em; +} + +.title .tag, +.subtitle .tag { + vertical-align: middle; +} + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; +} + +.title strong { + color: inherit; + font-weight: inherit; +} + +.title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; +} + +.title.is-1 { + font-size: 3rem; +} + +.title.is-2 { + font-size: 2.5rem; +} + +.title.is-3 { + font-size: 2rem; +} + +.title.is-4 { + font-size: 1.5rem; +} + +.title.is-5 { + font-size: 1.25rem; +} + +.title.is-6 { + font-size: 1rem; +} + +.title.is-7 { + font-size: 0.75rem; +} + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; +} + +.subtitle strong { + color: #363636; + font-weight: 600; +} + +.subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; +} + +.subtitle.is-1 { + font-size: 3rem; +} + +.subtitle.is-2 { + font-size: 2.5rem; +} + +.subtitle.is-3 { + font-size: 2rem; +} + +.subtitle.is-4 { + font-size: 1.5rem; +} + +.subtitle.is-5 { + font-size: 1.25rem; +} + +.subtitle.is-6 { + font-size: 1rem; +} + +.subtitle.is-7 { + font-size: 0.75rem; +} + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; +} + +.number { + align-items: center; + background-color: whitesmoke; + border-radius: 9999px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; +} + +/* Bulma Form */ +.input, .textarea, .select select { + background-color: white; + border-color: #dbdbdb; + border-radius: 4px; + color: #363636; +} + +.input::-moz-placeholder, .textarea::-moz-placeholder, .select select::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input::-webkit-input-placeholder, .textarea::-webkit-input-placeholder, .select select::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:-moz-placeholder, .textarea:-moz-placeholder, .select select:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:-ms-input-placeholder, .textarea:-ms-input-placeholder, .select select:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); +} + +.input:hover, .textarea:hover, .select select:hover, .is-hovered.input, .is-hovered.textarea, .select select.is-hovered { + border-color: #b5b5b5; +} + +.input:focus, .textarea:focus, .select select:focus, .is-focused.input, .is-focused.textarea, .select select.is-focused, .input:active, .textarea:active, .select select:active, .is-active.input, .is-active.textarea, .select select.is-active { + border-color: #485fc7; + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.input[disabled], .textarea[disabled], .select select[disabled], +fieldset[disabled] .input, +fieldset[disabled] .textarea, +fieldset[disabled] .select select, +.select fieldset[disabled] select { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; +} + +.input[disabled]::-moz-placeholder, .textarea[disabled]::-moz-placeholder, .select select[disabled]::-moz-placeholder, +fieldset[disabled] .input::-moz-placeholder, +fieldset[disabled] .textarea::-moz-placeholder, +fieldset[disabled] .select select::-moz-placeholder, +.select fieldset[disabled] select::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]::-webkit-input-placeholder, .textarea[disabled]::-webkit-input-placeholder, .select select[disabled]::-webkit-input-placeholder, +fieldset[disabled] .input::-webkit-input-placeholder, +fieldset[disabled] .textarea::-webkit-input-placeholder, +fieldset[disabled] .select select::-webkit-input-placeholder, +.select fieldset[disabled] select::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]:-moz-placeholder, .textarea[disabled]:-moz-placeholder, .select select[disabled]:-moz-placeholder, +fieldset[disabled] .input:-moz-placeholder, +fieldset[disabled] .textarea:-moz-placeholder, +fieldset[disabled] .select select:-moz-placeholder, +.select fieldset[disabled] select:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input[disabled]:-ms-input-placeholder, .textarea[disabled]:-ms-input-placeholder, .select select[disabled]:-ms-input-placeholder, +fieldset[disabled] .input:-ms-input-placeholder, +fieldset[disabled] .textarea:-ms-input-placeholder, +fieldset[disabled] .select select:-ms-input-placeholder, +.select fieldset[disabled] select:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); +} + +.input, .textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(10, 10, 10, 0.05); + max-width: 100%; + width: 100%; +} + +.input[readonly], .textarea[readonly] { + box-shadow: none; +} + +.is-white.input, .is-white.textarea { + border-color: white; +} + +.is-white.input:focus, .is-white.textarea:focus, .is-white.is-focused.input, .is-white.is-focused.textarea, .is-white.input:active, .is-white.textarea:active, .is-white.is-active.input, .is-white.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.is-black.input, .is-black.textarea { + border-color: #0a0a0a; +} + +.is-black.input:focus, .is-black.textarea:focus, .is-black.is-focused.input, .is-black.is-focused.textarea, .is-black.input:active, .is-black.textarea:active, .is-black.is-active.input, .is-black.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.is-light.input, .is-light.textarea { + border-color: whitesmoke; +} + +.is-light.input:focus, .is-light.textarea:focus, .is-light.is-focused.input, .is-light.is-focused.textarea, .is-light.input:active, .is-light.textarea:active, .is-light.is-active.input, .is-light.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.is-dark.input, .is-dark.textarea { + border-color: #363636; +} + +.is-dark.input:focus, .is-dark.textarea:focus, .is-dark.is-focused.input, .is-dark.is-focused.textarea, .is-dark.input:active, .is-dark.textarea:active, .is-dark.is-active.input, .is-dark.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.is-primary.input, .is-primary.textarea { + border-color: #00d1b2; +} + +.is-primary.input:focus, .is-primary.textarea:focus, .is-primary.is-focused.input, .is-primary.is-focused.textarea, .is-primary.input:active, .is-primary.textarea:active, .is-primary.is-active.input, .is-primary.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.is-link.input, .is-link.textarea { + border-color: #485fc7; +} + +.is-link.input:focus, .is-link.textarea:focus, .is-link.is-focused.input, .is-link.is-focused.textarea, .is-link.input:active, .is-link.textarea:active, .is-link.is-active.input, .is-link.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.is-info.input, .is-info.textarea { + border-color: #3e8ed0; +} + +.is-info.input:focus, .is-info.textarea:focus, .is-info.is-focused.input, .is-info.is-focused.textarea, .is-info.input:active, .is-info.textarea:active, .is-info.is-active.input, .is-info.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.is-success.input, .is-success.textarea { + border-color: #48c78e; +} + +.is-success.input:focus, .is-success.textarea:focus, .is-success.is-focused.input, .is-success.is-focused.textarea, .is-success.input:active, .is-success.textarea:active, .is-success.is-active.input, .is-success.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.is-warning.input, .is-warning.textarea { + border-color: #ffe08a; +} + +.is-warning.input:focus, .is-warning.textarea:focus, .is-warning.is-focused.input, .is-warning.is-focused.textarea, .is-warning.input:active, .is-warning.textarea:active, .is-warning.is-active.input, .is-warning.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.is-danger.input, .is-danger.textarea { + border-color: #f14668; +} + +.is-danger.input:focus, .is-danger.textarea:focus, .is-danger.is-focused.input, .is-danger.is-focused.textarea, .is-danger.input:active, .is-danger.textarea:active, .is-danger.is-active.input, .is-danger.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.is-small.input, .is-small.textarea { + border-radius: 2px; + font-size: 0.75rem; +} + +.is-medium.input, .is-medium.textarea { + font-size: 1.25rem; +} + +.is-large.input, .is-large.textarea { + font-size: 1.5rem; +} + +.is-fullwidth.input, .is-fullwidth.textarea { + display: block; + width: 100%; +} + +.is-inline.input, .is-inline.textarea { + display: inline; + width: auto; +} + +.input.is-rounded { + border-radius: 9999px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); +} + +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; +} + +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; +} + +.textarea:not([rows]) { + max-height: 40em; + min-height: 8em; +} + +.textarea[rows] { + height: initial; +} + +.textarea.has-fixed-size { + resize: none; +} + +.checkbox, .radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; +} + +.checkbox input, .radio input { + cursor: pointer; +} + +.checkbox:hover, .radio:hover { + color: #363636; +} + +.checkbox[disabled], .radio[disabled], +fieldset[disabled] .checkbox, +fieldset[disabled] .radio, +.checkbox input[disabled], +.radio input[disabled] { + color: #7a7a7a; + cursor: not-allowed; +} + +.radio + .radio { + margin-left: 0.5em; +} + +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; +} + +.select:not(.is-multiple) { + height: 2.5em; +} + +.select:not(.is-multiple):not(.is-loading)::after { + border-color: #485fc7; + right: 1.125em; + z-index: 4; +} + +.select.is-rounded select { + border-radius: 9999px; + padding-left: 1em; +} + +.select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; +} + +.select select::-ms-expand { + display: none; +} + +.select select[disabled]:hover, +fieldset[disabled] .select select:hover { + border-color: whitesmoke; +} + +.select select:not([multiple]) { + padding-right: 2.5em; +} + +.select select[multiple] { + height: auto; + padding: 0; +} + +.select select[multiple] option { + padding: 0.5em 1em; +} + +.select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; +} + +.select.is-white:not(:hover)::after { + border-color: white; +} + +.select.is-white select { + border-color: white; +} + +.select.is-white select:hover, .select.is-white select.is-hovered { + border-color: #f2f2f2; +} + +.select.is-white select:focus, .select.is-white select.is-focused, .select.is-white select:active, .select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); +} + +.select.is-black:not(:hover)::after { + border-color: #0a0a0a; +} + +.select.is-black select { + border-color: #0a0a0a; +} + +.select.is-black select:hover, .select.is-black select.is-hovered { + border-color: black; +} + +.select.is-black select:focus, .select.is-black select.is-focused, .select.is-black select:active, .select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); +} + +.select.is-light:not(:hover)::after { + border-color: whitesmoke; +} + +.select.is-light select { + border-color: whitesmoke; +} + +.select.is-light select:hover, .select.is-light select.is-hovered { + border-color: #e8e8e8; +} + +.select.is-light select:focus, .select.is-light select.is-focused, .select.is-light select:active, .select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); +} + +.select.is-dark:not(:hover)::after { + border-color: #363636; +} + +.select.is-dark select { + border-color: #363636; +} + +.select.is-dark select:hover, .select.is-dark select.is-hovered { + border-color: #292929; +} + +.select.is-dark select:focus, .select.is-dark select.is-focused, .select.is-dark select:active, .select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); +} + +.select.is-primary:not(:hover)::after { + border-color: #00d1b2; +} + +.select.is-primary select { + border-color: #00d1b2; +} + +.select.is-primary select:hover, .select.is-primary select.is-hovered { + border-color: #00b89c; +} + +.select.is-primary select:focus, .select.is-primary select.is-focused, .select.is-primary select:active, .select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); +} + +.select.is-link:not(:hover)::after { + border-color: #485fc7; +} + +.select.is-link select { + border-color: #485fc7; +} + +.select.is-link select:hover, .select.is-link select.is-hovered { + border-color: #3a51bb; +} + +.select.is-link select:focus, .select.is-link select.is-focused, .select.is-link select:active, .select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 95, 199, 0.25); +} + +.select.is-info:not(:hover)::after { + border-color: #3e8ed0; +} + +.select.is-info select { + border-color: #3e8ed0; +} + +.select.is-info select:hover, .select.is-info select.is-hovered { + border-color: #3082c5; +} + +.select.is-info select:focus, .select.is-info select.is-focused, .select.is-info select:active, .select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(62, 142, 208, 0.25); +} + +.select.is-success:not(:hover)::after { + border-color: #48c78e; +} + +.select.is-success select { + border-color: #48c78e; +} + +.select.is-success select:hover, .select.is-success select.is-hovered { + border-color: #3abb81; +} + +.select.is-success select:focus, .select.is-success select.is-focused, .select.is-success select:active, .select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 199, 142, 0.25); +} + +.select.is-warning:not(:hover)::after { + border-color: #ffe08a; +} + +.select.is-warning select { + border-color: #ffe08a; +} + +.select.is-warning select:hover, .select.is-warning select.is-hovered { + border-color: #ffd970; +} + +.select.is-warning select:focus, .select.is-warning select.is-focused, .select.is-warning select:active, .select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 224, 138, 0.25); +} + +.select.is-danger:not(:hover)::after { + border-color: #f14668; +} + +.select.is-danger select { + border-color: #f14668; +} + +.select.is-danger select:hover, .select.is-danger select.is-hovered { + border-color: #ef2e55; +} + +.select.is-danger select:focus, .select.is-danger select.is-focused, .select.is-danger select:active, .select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); +} + +.select.is-small { + border-radius: 2px; + font-size: 0.75rem; +} + +.select.is-medium { + font-size: 1.25rem; +} + +.select.is-large { + font-size: 1.5rem; +} + +.select.is-disabled::after { + border-color: #7a7a7a !important; + opacity: 0.5; +} + +.select.is-fullwidth { + width: 100%; +} + +.select.is-fullwidth select { + width: 100%; +} + +.select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; +} + +.select.is-loading.is-small:after { + font-size: 0.75rem; +} + +.select.is-loading.is-medium:after { + font-size: 1.25rem; +} + +.select.is-loading.is-large:after { + font-size: 1.5rem; +} + +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; +} + +.file.is-white .file-cta { + background-color: white; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-white:hover .file-cta, .file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-white:focus .file-cta, .file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.25); + color: #0a0a0a; +} + +.file.is-white:active .file-cta, .file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; +} + +.file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: white; +} + +.file.is-black:hover .file-cta, .file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: white; +} + +.file.is-black:focus .file-cta, .file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10, 10, 10, 0.25); + color: white; +} + +.file.is-black:active .file-cta, .file.is-black.is-active .file-cta { + background-color: black; + border-color: transparent; + color: white; +} + +.file.is-light .file-cta { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:hover .file-cta, .file.is-light.is-hovered .file-cta { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:focus .file-cta, .file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245, 245, 245, 0.25); + color: rgba(0, 0, 0, 0.7); +} + +.file.is-light:active .file-cta, .file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; +} + +.file.is-dark:hover .file-cta, .file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; +} + +.file.is-dark:focus .file-cta, .file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54, 54, 54, 0.25); + color: #fff; +} + +.file.is-dark:active .file-cta, .file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; +} + +.file.is-primary .file-cta { + background-color: #00d1b2; + border-color: transparent; + color: #fff; +} + +.file.is-primary:hover .file-cta, .file.is-primary.is-hovered .file-cta { + background-color: #00c4a7; + border-color: transparent; + color: #fff; +} + +.file.is-primary:focus .file-cta, .file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0, 209, 178, 0.25); + color: #fff; +} + +.file.is-primary:active .file-cta, .file.is-primary.is-active .file-cta { + background-color: #00b89c; + border-color: transparent; + color: #fff; +} + +.file.is-link .file-cta { + background-color: #485fc7; + border-color: transparent; + color: #fff; +} + +.file.is-link:hover .file-cta, .file.is-link.is-hovered .file-cta { + background-color: #3e56c4; + border-color: transparent; + color: #fff; +} + +.file.is-link:focus .file-cta, .file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 95, 199, 0.25); + color: #fff; +} + +.file.is-link:active .file-cta, .file.is-link.is-active .file-cta { + background-color: #3a51bb; + border-color: transparent; + color: #fff; +} + +.file.is-info .file-cta { + background-color: #3e8ed0; + border-color: transparent; + color: #fff; +} + +.file.is-info:hover .file-cta, .file.is-info.is-hovered .file-cta { + background-color: #3488ce; + border-color: transparent; + color: #fff; +} + +.file.is-info:focus .file-cta, .file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(62, 142, 208, 0.25); + color: #fff; +} + +.file.is-info:active .file-cta, .file.is-info.is-active .file-cta { + background-color: #3082c5; + border-color: transparent; + color: #fff; +} + +.file.is-success .file-cta { + background-color: #48c78e; + border-color: transparent; + color: #fff; +} + +.file.is-success:hover .file-cta, .file.is-success.is-hovered .file-cta { + background-color: #3ec487; + border-color: transparent; + color: #fff; +} + +.file.is-success:focus .file-cta, .file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 199, 142, 0.25); + color: #fff; +} + +.file.is-success:active .file-cta, .file.is-success.is-active .file-cta { + background-color: #3abb81; + border-color: transparent; + color: #fff; +} + +.file.is-warning .file-cta { + background-color: #ffe08a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:hover .file-cta, .file.is-warning.is-hovered .file-cta { + background-color: #ffdc7d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:focus .file-cta, .file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 224, 138, 0.25); + color: rgba(0, 0, 0, 0.7); +} + +.file.is-warning:active .file-cta, .file.is-warning.is-active .file-cta { + background-color: #ffd970; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); +} + +.file.is-danger .file-cta { + background-color: #f14668; + border-color: transparent; + color: #fff; +} + +.file.is-danger:hover .file-cta, .file.is-danger.is-hovered .file-cta { + background-color: #f03a5f; + border-color: transparent; + color: #fff; +} + +.file.is-danger:focus .file-cta, .file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(241, 70, 104, 0.25); + color: #fff; +} + +.file.is-danger:active .file-cta, .file.is-danger.is-active .file-cta { + background-color: #ef2e55; + border-color: transparent; + color: #fff; +} + +.file.is-small { + font-size: 0.75rem; +} + +.file.is-normal { + font-size: 1rem; +} + +.file.is-medium { + font-size: 1.25rem; +} + +.file.is-medium .file-icon .fa { + font-size: 21px; +} + +.file.is-large { + font-size: 1.5rem; +} + +.file.is-large .file-icon .fa { + font-size: 28px; +} + +.file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.file.has-name.is-empty .file-cta { + border-radius: 4px; +} + +.file.has-name.is-empty .file-name { + display: none; +} + +.file.is-boxed .file-label { + flex-direction: column; +} + +.file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; +} + +.file.is-boxed .file-name { + border-width: 0 1px 1px; +} + +.file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; +} + +.file.is-boxed .file-icon .fa { + font-size: 21px; +} + +.file.is-boxed.is-small .file-icon .fa { + font-size: 14px; +} + +.file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; +} + +.file.is-boxed.is-large .file-icon .fa { + font-size: 35px; +} + +.file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; +} + +.file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; +} + +.file.is-centered { + justify-content: center; +} + +.file.is-fullwidth .file-label { + width: 100%; +} + +.file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; +} + +.file.is-right { + justify-content: flex-end; +} + +.file.is-right .file-cta { + border-radius: 0 4px 4px 0; +} + +.file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; +} + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; +} + +.file-label:hover .file-cta { + background-color: #eeeeee; + color: #363636; +} + +.file-label:hover .file-name { + border-color: #d5d5d5; +} + +.file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; +} + +.file-label:active .file-name { + border-color: #cfcfcf; +} + +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; +} + +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; +} + +.file-cta { + background-color: whitesmoke; + color: #4a4a4a; +} + +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: inherit; + text-overflow: ellipsis; +} + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; +} + +.file-icon .fa { + font-size: 14px; +} + +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; +} + +.label:not(:last-child) { + margin-bottom: 0.5em; +} + +.label.is-small { + font-size: 0.75rem; +} + +.label.is-medium { + font-size: 1.25rem; +} + +.label.is-large { + font-size: 1.5rem; +} + +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; +} + +.help.is-white { + color: white; +} + +.help.is-black { + color: #0a0a0a; +} + +.help.is-light { + color: whitesmoke; +} + +.help.is-dark { + color: #363636; +} + +.help.is-primary { + color: #00d1b2; +} + +.help.is-link { + color: #485fc7; +} + +.help.is-info { + color: #3e8ed0; +} + +.help.is-success { + color: #48c78e; +} + +.help.is-warning { + color: #ffe08a; +} + +.help.is-danger { + color: #f14668; +} + +.field:not(:last-child) { + margin-bottom: 0.75rem; +} + +.field.has-addons { + display: flex; + justify-content: flex-start; +} + +.field.has-addons .control:not(:last-child) { + margin-right: -1px; +} + +.field.has-addons .control:not(:first-child):not(:last-child) .button, +.field.has-addons .control:not(:first-child):not(:last-child) .input, +.field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; +} + +.field.has-addons .control:first-child:not(:only-child) .button, +.field.has-addons .control:first-child:not(:only-child) .input, +.field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} + +.field.has-addons .control:last-child:not(:only-child) .button, +.field.has-addons .control:last-child:not(:only-child) .input, +.field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} + +.field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, +.field.has-addons .control .input:not([disabled]):hover, +.field.has-addons .control .input:not([disabled]).is-hovered, +.field.has-addons .control .select select:not([disabled]):hover, +.field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; +} + +.field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, +.field.has-addons .control .input:not([disabled]):focus, +.field.has-addons .control .input:not([disabled]).is-focused, +.field.has-addons .control .input:not([disabled]):active, +.field.has-addons .control .input:not([disabled]).is-active, +.field.has-addons .control .select select:not([disabled]):focus, +.field.has-addons .control .select select:not([disabled]).is-focused, +.field.has-addons .control .select select:not([disabled]):active, +.field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; +} + +.field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, +.field.has-addons .control .input:not([disabled]):focus:hover, +.field.has-addons .control .input:not([disabled]).is-focused:hover, +.field.has-addons .control .input:not([disabled]):active:hover, +.field.has-addons .control .input:not([disabled]).is-active:hover, +.field.has-addons .control .select select:not([disabled]):focus:hover, +.field.has-addons .control .select select:not([disabled]).is-focused:hover, +.field.has-addons .control .select select:not([disabled]):active:hover, +.field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; +} + +.field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.field.has-addons.has-addons-centered { + justify-content: center; +} + +.field.has-addons.has-addons-right { + justify-content: flex-end; +} + +.field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; +} + +.field.is-grouped { + display: flex; + justify-content: flex-start; +} + +.field.is-grouped > .control { + flex-shrink: 0; +} + +.field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} + +.field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.field.is-grouped.is-grouped-centered { + justify-content: center; +} + +.field.is-grouped.is-grouped-right { + justify-content: flex-end; +} + +.field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; +} + +.field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; +} + +.field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; +} + +.field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; + } +} + +.field-label .label { + font-size: inherit; +} + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} + +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; + } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; + } +} + +.field-body .field .field { + margin-bottom: 0; +} + +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body > .field { + flex-shrink: 1; + } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; + } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; + } +} + +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: inherit; +} + +.control.has-icons-left .input:focus ~ .icon, +.control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, +.control.has-icons-right .select:focus ~ .icon { + color: #4a4a4a; +} + +.control.has-icons-left .input.is-small ~ .icon, +.control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, +.control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; +} + +.control.has-icons-left .input.is-medium ~ .icon, +.control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, +.control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; +} + +.control.has-icons-left .input.is-large ~ .icon, +.control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, +.control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; +} + +.control.has-icons-left .icon, .control.has-icons-right .icon { + color: #dbdbdb; + height: 2.5em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.5em; + z-index: 4; +} + +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: 2.5em; +} + +.control.has-icons-left .icon.is-left { + left: 0; +} + +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: 2.5em; +} + +.control.has-icons-right .icon.is-right { + right: 0; +} + +.control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; +} + +.control.is-loading.is-small:after { + font-size: 0.75rem; +} + +.control.is-loading.is-medium:after { + font-size: 1.25rem; +} + +.control.is-loading.is-large:after { + font-size: 1.5rem; +} + +/* Bulma Components */ +.breadcrumb { + font-size: 1rem; + white-space: nowrap; +} + +.breadcrumb a { + align-items: center; + color: #485fc7; + display: flex; + justify-content: center; + padding: 0 0.75em; +} + +.breadcrumb a:hover { + color: #363636; +} + +.breadcrumb li { + align-items: center; + display: flex; +} + +.breadcrumb li:first-child a { + padding-left: 0; +} + +.breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; +} + +.breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; +} + +.breadcrumb ul, +.breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.breadcrumb .icon:first-child { + margin-right: 0.5em; +} + +.breadcrumb .icon:last-child { + margin-left: 0.5em; +} + +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + justify-content: center; +} + +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + justify-content: flex-end; +} + +.breadcrumb.is-small { + font-size: 0.75rem; +} + +.breadcrumb.is-medium { + font-size: 1.25rem; +} + +.breadcrumb.is-large { + font-size: 1.5rem; +} + +.breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; +} + +.breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; +} + +.breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; +} + +.breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; +} + +.card { + background-color: white; + border-radius: 0.25rem; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + max-width: 100%; + position: relative; +} + +.card-header:first-child, .card-content:first-child, .card-footer:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-header:last-child, .card-content:last-child, .card-footer:last-child { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(10, 10, 10, 0.1); + display: flex; +} + +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; +} + +.card-header-title.is-centered { + justify-content: center; +} + +.card-header-icon { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + color: currentColor; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; +} + +.card-image { + display: block; + position: relative; +} + +.card-image:first-child img { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-image:last-child img { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; +} + +.card-content { + background-color: transparent; + padding: 1.5rem; +} + +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; +} + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; +} + +.card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; +} + +.card .media:not(:last-child) { + margin-bottom: 1.5rem; +} + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; +} + +.dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} + +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} + +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; +} + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; +} + +.dropdown-content { + background-color: white; + border-radius: 4px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; +} + +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: inherit; + white-space: nowrap; + width: 100%; +} + +a.dropdown-item:hover, +button.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; +} + +a.dropdown-item.is-active, +button.dropdown-item.is-active { + background-color: #485fc7; + color: #fff; +} + +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} + +.level { + align-items: center; + justify-content: space-between; +} + +.level code { + border-radius: 4px; +} + +.level img { + display: inline-block; + vertical-align: top; +} + +.level.is-mobile { + display: flex; +} + +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: flex; +} + +.level.is-mobile .level-left + .level-right { + margin-top: 0; +} + +.level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; +} + +.level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; +} + +@media screen and (min-width: 769px), print { + .level { + display: flex; + } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; + } +} + +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; +} + +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} + +@media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} + +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + flex-grow: 1; +} + +@media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; + } +} + +.level-left { + align-items: center; + justify-content: flex-start; +} + +@media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; + } +} + +@media screen and (min-width: 769px), print { + .level-left { + display: flex; + } +} + +.level-right { + align-items: center; + justify-content: flex-end; +} + +@media screen and (min-width: 769px), print { + .level-right { + display: flex; + } +} + +.media { + align-items: flex-start; + display: flex; + text-align: inherit; +} + +.media .content:not(:last-child) { + margin-bottom: 0.75rem; +} + +.media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: flex; + padding-top: 0.75rem; +} + +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: 0.5rem; +} + +.media .media .media { + padding-top: 0.5rem; +} + +.media .media .media + .media { + margin-top: 0.5rem; +} + +.media + .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; +} + +.media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; +} + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} + +.media-left { + margin-right: 1rem; +} + +.media-right { + margin-left: 1rem; +} + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: inherit; +} + +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; + } +} + +.menu { + font-size: 1rem; +} + +.menu.is-small { + font-size: 0.75rem; +} + +.menu.is-medium { + font-size: 1.25rem; +} + +.menu.is-large { + font-size: 1.5rem; +} + +.menu-list { + line-height: 1.25; +} + +.menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; +} + +.menu-list a:hover { + background-color: whitesmoke; + color: #363636; +} + +.menu-list a.is-active { + background-color: #485fc7; + color: #fff; +} + +.menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; +} + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.menu-label:not(:first-child) { + margin-top: 1em; +} + +.menu-label:not(:last-child) { + margin-bottom: 1em; +} + +.message { + background-color: whitesmoke; + border-radius: 4px; + font-size: 1rem; +} + +.message strong { + color: currentColor; +} + +.message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} + +.message.is-small { + font-size: 0.75rem; +} + +.message.is-medium { + font-size: 1.25rem; +} + +.message.is-large { + font-size: 1.5rem; +} + +.message.is-white { + background-color: white; +} + +.message.is-white .message-header { + background-color: white; + color: #0a0a0a; +} + +.message.is-white .message-body { + border-color: white; +} + +.message.is-black { + background-color: #fafafa; +} + +.message.is-black .message-header { + background-color: #0a0a0a; + color: white; +} + +.message.is-black .message-body { + border-color: #0a0a0a; +} + +.message.is-light { + background-color: #fafafa; +} + +.message.is-light .message-header { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.message.is-light .message-body { + border-color: whitesmoke; +} + +.message.is-dark { + background-color: #fafafa; +} + +.message.is-dark .message-header { + background-color: #363636; + color: #fff; +} + +.message.is-dark .message-body { + border-color: #363636; +} + +.message.is-primary { + background-color: #ebfffc; +} + +.message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; +} + +.message.is-primary .message-body { + border-color: #00d1b2; + color: #00947e; +} + +.message.is-link { + background-color: #eff1fa; +} + +.message.is-link .message-header { + background-color: #485fc7; + color: #fff; +} + +.message.is-link .message-body { + border-color: #485fc7; + color: #3850b7; +} + +.message.is-info { + background-color: #eff5fb; +} + +.message.is-info .message-header { + background-color: #3e8ed0; + color: #fff; +} + +.message.is-info .message-body { + border-color: #3e8ed0; + color: #296fa8; +} + +.message.is-success { + background-color: #effaf5; +} + +.message.is-success .message-header { + background-color: #48c78e; + color: #fff; +} + +.message.is-success .message-body { + border-color: #48c78e; + color: #257953; +} + +.message.is-warning { + background-color: #fffaeb; +} + +.message.is-warning .message-header { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.message.is-warning .message-body { + border-color: #ffe08a; + color: #946c00; +} + +.message.is-danger { + background-color: #feecf0; +} + +.message.is-danger .message-header { + background-color: #f14668; + color: #fff; +} + +.message.is-danger .message-body { + border-color: #f14668; + color: #cc0f35; +} + +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; +} + +.message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; +} + +.message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; +} + +.message-body code, +.message-body pre { + background-color: white; +} + +.message-body pre code { + background-color: transparent; +} + +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; +} + +.modal.is-active { + display: flex; +} + +.modal-background { + background-color: rgba(10, 10, 10, 0.86); +} + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; +} + +@media screen and (min-width: 769px) { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; + } +} + +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; +} + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; +} + +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: whitesmoke; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; +} + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; +} + +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; +} + +.modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; +} + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; +} + +.navbar { + background-color: white; + min-height: 3.25rem; + position: relative; + z-index: 30; +} + +.navbar.is-white { + background-color: white; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand > .navbar-item, +.navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand > a.navbar-item:focus, .navbar.is-white .navbar-brand > a.navbar-item:hover, .navbar.is-white .navbar-brand > a.navbar-item.is-active, +.navbar.is-white .navbar-brand .navbar-link:focus, +.navbar.is-white .navbar-brand .navbar-link:hover, +.navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; +} + +.navbar.is-white .navbar-burger { + color: #0a0a0a; +} + +@media screen and (min-width: 1024px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; + } + .navbar.is-white .navbar-start > a.navbar-item:focus, .navbar.is-white .navbar-start > a.navbar-item:hover, .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; + } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; + } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; + } +} + +.navbar.is-black { + background-color: #0a0a0a; + color: white; +} + +.navbar.is-black .navbar-brand > .navbar-item, +.navbar.is-black .navbar-brand .navbar-link { + color: white; +} + +.navbar.is-black .navbar-brand > a.navbar-item:focus, .navbar.is-black .navbar-brand > a.navbar-item:hover, .navbar.is-black .navbar-brand > a.navbar-item.is-active, +.navbar.is-black .navbar-brand .navbar-link:focus, +.navbar.is-black .navbar-brand .navbar-link:hover, +.navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; +} + +.navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; +} + +.navbar.is-black .navbar-burger { + color: white; +} + +@media screen and (min-width: 1024px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; + } + .navbar.is-black .navbar-start > a.navbar-item:focus, .navbar.is-black .navbar-start > a.navbar-item:hover, .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; + } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; + } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; + } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; + } +} + +.navbar.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand > .navbar-item, +.navbar.is-light .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand > a.navbar-item:focus, .navbar.is-light .navbar-brand > a.navbar-item:hover, .navbar.is-light .navbar-brand > a.navbar-item.is-active, +.navbar.is-light .navbar-brand .navbar-link:focus, +.navbar.is-light .navbar-brand .navbar-link:hover, +.navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-light .navbar-burger { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (min-width: 1024px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-start > a.navbar-item:focus, .navbar.is-light .navbar-start > a.navbar-item:hover, .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); + } +} + +.navbar.is-dark { + background-color: #363636; + color: #fff; +} + +.navbar.is-dark .navbar-brand > .navbar-item, +.navbar.is-dark .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-dark .navbar-brand > a.navbar-item:focus, .navbar.is-dark .navbar-brand > a.navbar-item:hover, .navbar.is-dark .navbar-brand > a.navbar-item.is-active, +.navbar.is-dark .navbar-brand .navbar-link:focus, +.navbar.is-dark .navbar-brand .navbar-link:hover, +.navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; +} + +.navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-dark .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-dark .navbar-start > a.navbar-item:focus, .navbar.is-dark .navbar-start > a.navbar-item:hover, .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; + } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; + } +} + +.navbar.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.navbar.is-primary .navbar-brand > .navbar-item, +.navbar.is-primary .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-primary .navbar-brand > a.navbar-item:focus, .navbar.is-primary .navbar-brand > a.navbar-item:hover, .navbar.is-primary .navbar-brand > a.navbar-item.is-active, +.navbar.is-primary .navbar-brand .navbar-link:focus, +.navbar.is-primary .navbar-brand .navbar-link:hover, +.navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-primary .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-primary .navbar-start > a.navbar-item:focus, .navbar.is-primary .navbar-start > a.navbar-item:hover, .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; + } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; + } +} + +.navbar.is-link { + background-color: #485fc7; + color: #fff; +} + +.navbar.is-link .navbar-brand > .navbar-item, +.navbar.is-link .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-link .navbar-brand > a.navbar-item:focus, .navbar.is-link .navbar-brand > a.navbar-item:hover, .navbar.is-link .navbar-brand > a.navbar-item.is-active, +.navbar.is-link .navbar-brand .navbar-link:focus, +.navbar.is-link .navbar-brand .navbar-link:hover, +.navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; +} + +.navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-link .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-link .navbar-start > a.navbar-item:focus, .navbar.is-link .navbar-start > a.navbar-item:hover, .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; + } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3a51bb; + color: #fff; + } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #485fc7; + color: #fff; + } +} + +.navbar.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.navbar.is-info .navbar-brand > .navbar-item, +.navbar.is-info .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-info .navbar-brand > a.navbar-item:focus, .navbar.is-info .navbar-brand > a.navbar-item:hover, .navbar.is-info .navbar-brand > a.navbar-item.is-active, +.navbar.is-info .navbar-brand .navbar-link:focus, +.navbar.is-info .navbar-brand .navbar-link:hover, +.navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #3082c5; + color: #fff; +} + +.navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-info .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-info .navbar-start > a.navbar-item:focus, .navbar.is-info .navbar-start > a.navbar-item:hover, .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #3082c5; + color: #fff; + } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3082c5; + color: #fff; + } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #3e8ed0; + color: #fff; + } +} + +.navbar.is-success { + background-color: #48c78e; + color: #fff; +} + +.navbar.is-success .navbar-brand > .navbar-item, +.navbar.is-success .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-success .navbar-brand > a.navbar-item:focus, .navbar.is-success .navbar-brand > a.navbar-item:hover, .navbar.is-success .navbar-brand > a.navbar-item.is-active, +.navbar.is-success .navbar-brand .navbar-link:focus, +.navbar.is-success .navbar-brand .navbar-link:hover, +.navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #3abb81; + color: #fff; +} + +.navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-success .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-success .navbar-start > a.navbar-item:focus, .navbar.is-success .navbar-start > a.navbar-item:hover, .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #3abb81; + color: #fff; + } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3abb81; + color: #fff; + } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #48c78e; + color: #fff; + } +} + +.navbar.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand > .navbar-item, +.navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand > a.navbar-item:focus, .navbar.is-warning .navbar-brand > a.navbar-item:hover, .navbar.is-warning .navbar-brand > a.navbar-item.is-active, +.navbar.is-warning .navbar-brand .navbar-link:focus, +.navbar.is-warning .navbar-brand .navbar-link:hover, +.navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); +} + +.navbar.is-warning .navbar-burger { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (min-width: 1024px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start > a.navbar-item:focus, .navbar.is-warning .navbar-start > a.navbar-item:hover, .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); + } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); + } +} + +.navbar.is-danger { + background-color: #f14668; + color: #fff; +} + +.navbar.is-danger .navbar-brand > .navbar-item, +.navbar.is-danger .navbar-brand .navbar-link { + color: #fff; +} + +.navbar.is-danger .navbar-brand > a.navbar-item:focus, .navbar.is-danger .navbar-brand > a.navbar-item:hover, .navbar.is-danger .navbar-brand > a.navbar-item.is-active, +.navbar.is-danger .navbar-brand .navbar-link:focus, +.navbar.is-danger .navbar-brand .navbar-link:hover, +.navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} + +.navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; +} + +.navbar.is-danger .navbar-burger { + color: #fff; +} + +@media screen and (min-width: 1024px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; + } + .navbar.is-danger .navbar-start > a.navbar-item:focus, .navbar.is-danger .navbar-start > a.navbar-item:hover, .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; + } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ef2e55; + color: #fff; + } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #f14668; + color: #fff; + } +} + +.navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; +} + +.navbar.has-shadow { + box-shadow: 0 2px 0 0 whitesmoke; +} + +.navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; +} + +.navbar.is-fixed-bottom { + bottom: 0; +} + +.navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 whitesmoke; +} + +.navbar.is-fixed-top { + top: 0; +} + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; +} + +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; +} + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; +} + +.navbar-brand a.navbar-item:focus, .navbar-brand a.navbar-item:hover { + background-color: transparent; +} + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} + +.navbar-burger { + color: #4a4a4a; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + background: none; + border: none; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; +} + +.navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; +} + +.navbar-burger span:nth-child(1) { + top: calc(50% - 6px); +} + +.navbar-burger span:nth-child(2) { + top: calc(50% - 1px); +} + +.navbar-burger span:nth-child(3) { + top: calc(50% + 4px); +} + +.navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); +} + +.navbar-burger.is-active span:nth-child(2) { + opacity: 0; +} + +.navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); +} + +.navbar-menu { + display: none; +} + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; +} + +.navbar-item .icon:only-child, +.navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; +} + +a.navbar-item, +.navbar-link { + cursor: pointer; +} + +a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, a.navbar-item.is-active, +.navbar-link:focus, +.navbar-link:focus-within, +.navbar-link:hover, +.navbar-link.is-active { + background-color: #fafafa; + color: #485fc7; +} + +.navbar-item { + flex-grow: 0; + flex-shrink: 0; +} + +.navbar-item img { + max-height: 1.75rem; +} + +.navbar-item.has-dropdown { + padding: 0; +} + +.navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} + +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); +} + +.navbar-item.is-tab:focus, .navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #485fc7; +} + +.navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #485fc7; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #485fc7; + padding-bottom: calc(0.5rem - 3px); +} + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; +} + +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; +} + +.navbar-link:not(.is-arrowless)::after { + border-color: #485fc7; + margin-top: -0.375em; + right: 1.125em; +} + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; +} + +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.navbar-divider { + background-color: whitesmoke; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; +} + +@media screen and (max-width: 1023px) { + .navbar > .container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; + } + .navbar-link::after { + display: none; + } + .navbar-menu { + background-color: white; + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; + } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; + } +} + +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; + } + .navbar { + min-height: 3.25rem; + } + .navbar.is-spaced { + padding: 1rem 2rem; + } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; + } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; + } + .navbar.is-transparent a.navbar-item:focus, .navbar.is-transparent a.navbar-item:hover, .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #485fc7; + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; + } + .navbar-item.has-dropdown { + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + } + .navbar-start { + justify-content: flex-start; + margin-right: auto; + } + .navbar-end { + justify-content: flex-end; + margin-left: auto; + } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; + } + .navbar-dropdown a.navbar-item:focus, .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; + } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #485fc7; + } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -0.75rem; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -0.75rem; + } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; + } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; + } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; + } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; + } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #0a0a0a; + } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; + } + .navbar-item.has-dropdown:focus .navbar-link, .navbar-item.has-dropdown:hover .navbar-link, .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; + } +} + +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); +} + +.pagination { + font-size: 1rem; + margin: -0.25rem; +} + +.pagination.is-small { + font-size: 0.75rem; +} + +.pagination.is-medium { + font-size: 1.25rem; +} + +.pagination.is-large { + font-size: 1.5rem; +} + +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 9999px; +} + +.pagination.is-rounded .pagination-link { + border-radius: 9999px; +} + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.5em; +} + +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + border-color: #b5b5b5; + color: #363636; +} + +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + border-color: #485fc7; +} + +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); +} + +.pagination-previous[disabled], .pagination-previous.is-disabled, +.pagination-next[disabled], +.pagination-next.is-disabled, +.pagination-link[disabled], +.pagination-link.is-disabled { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; +} + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} + +.pagination-link.is-current { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; +} + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; +} + +.pagination-list { + flex-wrap: wrap; +} + +.pagination-list li { + list-style: none; +} + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; + } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; + } +} + +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; + } + .pagination-previous, + .pagination-next, + .pagination-link, + .pagination-ellipsis { + margin-bottom: 0; + margin-top: 0; + } + .pagination-previous { + order: 2; + } + .pagination-next { + order: 3; + } + .pagination { + justify-content: space-between; + margin-bottom: 0; + margin-top: 0; + } + .pagination.is-centered .pagination-previous { + order: 1; + } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; + } + .pagination.is-centered .pagination-next { + order: 3; + } + .pagination.is-right .pagination-previous { + order: 1; + } + .pagination.is-right .pagination-next { + order: 2; + } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; + } +} + +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + font-size: 1rem; +} + +.panel:not(:last-child) { + margin-bottom: 1.5rem; +} + +.panel.is-white .panel-heading { + background-color: white; + color: #0a0a0a; +} + +.panel.is-white .panel-tabs a.is-active { + border-bottom-color: white; +} + +.panel.is-white .panel-block.is-active .panel-icon { + color: white; +} + +.panel.is-black .panel-heading { + background-color: #0a0a0a; + color: white; +} + +.panel.is-black .panel-tabs a.is-active { + border-bottom-color: #0a0a0a; +} + +.panel.is-black .panel-block.is-active .panel-icon { + color: #0a0a0a; +} + +.panel.is-light .panel-heading { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.panel.is-light .panel-tabs a.is-active { + border-bottom-color: whitesmoke; +} + +.panel.is-light .panel-block.is-active .panel-icon { + color: whitesmoke; +} + +.panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; +} + +.panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; +} + +.panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; +} + +.panel.is-primary .panel-heading { + background-color: #00d1b2; + color: #fff; +} + +.panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #00d1b2; +} + +.panel.is-primary .panel-block.is-active .panel-icon { + color: #00d1b2; +} + +.panel.is-link .panel-heading { + background-color: #485fc7; + color: #fff; +} + +.panel.is-link .panel-tabs a.is-active { + border-bottom-color: #485fc7; +} + +.panel.is-link .panel-block.is-active .panel-icon { + color: #485fc7; +} + +.panel.is-info .panel-heading { + background-color: #3e8ed0; + color: #fff; +} + +.panel.is-info .panel-tabs a.is-active { + border-bottom-color: #3e8ed0; +} + +.panel.is-info .panel-block.is-active .panel-icon { + color: #3e8ed0; +} + +.panel.is-success .panel-heading { + background-color: #48c78e; + color: #fff; +} + +.panel.is-success .panel-tabs a.is-active { + border-bottom-color: #48c78e; +} + +.panel.is-success .panel-block.is-active .panel-icon { + color: #48c78e; +} + +.panel.is-warning .panel-heading { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ffe08a; +} + +.panel.is-warning .panel-block.is-active .panel-icon { + color: #ffe08a; +} + +.panel.is-danger .panel-heading { + background-color: #f14668; + color: #fff; +} + +.panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #f14668; +} + +.panel.is-danger .panel-block.is-active .panel-icon { + color: #f14668; +} + +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; +} + +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; +} + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; +} + +.panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; +} + +.panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; +} + +.panel-list a { + color: #4a4a4a; +} + +.panel-list a:hover { + color: #485fc7; +} + +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; +} + +.panel-block input[type="checkbox"] { + margin-right: 0.75em; +} + +.panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; +} + +.panel-block.is-wrapped { + flex-wrap: wrap; +} + +.panel-block.is-active { + border-left-color: #485fc7; + color: #363636; +} + +.panel-block.is-active .panel-icon { + color: #485fc7; +} + +.panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; +} + +a.panel-block, +label.panel-block { + cursor: pointer; +} + +a.panel-block:hover, +label.panel-block:hover { + background-color: whitesmoke; +} + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; +} + +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} + +.tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; +} + +.tabs a:hover { + border-bottom-color: #363636; + color: #363636; +} + +.tabs li { + display: block; +} + +.tabs li.is-active a { + border-bottom-color: #485fc7; + color: #485fc7; +} + +.tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; +} + +.tabs ul.is-left { + padding-right: 0.75em; +} + +.tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} + +.tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; +} + +.tabs .icon:first-child { + margin-right: 0.5em; +} + +.tabs .icon:last-child { + margin-left: 0.5em; +} + +.tabs.is-centered ul { + justify-content: center; +} + +.tabs.is-right ul { + justify-content: flex-end; +} + +.tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} + +.tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; +} + +.tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; +} + +.tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; +} + +.tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; +} + +.tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; +} + +.tabs.is-toggle li + li { + margin-left: -1px; +} + +.tabs.is-toggle li:first-child a { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.tabs.is-toggle li:last-child a { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.tabs.is-toggle li.is-active a { + background-color: #485fc7; + border-color: #485fc7; + color: #fff; + z-index: 1; +} + +.tabs.is-toggle ul { + border-bottom: none; +} + +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 9999px; + border-top-left-radius: 9999px; + padding-left: 1.25em; +} + +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 9999px; + border-top-right-radius: 9999px; + padding-right: 1.25em; +} + +.tabs.is-small { + font-size: 0.75rem; +} + +.tabs.is-medium { + font-size: 1.25rem; +} + +.tabs.is-large { + font-size: 1.5rem; +} + +/* Bulma Grid */ +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; +} + +.columns.is-mobile > .column.is-narrow { + flex: none; + width: unset; +} + +.columns.is-mobile > .column.is-full { + flex: none; + width: 100%; +} + +.columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; +} + +.columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; +} + +.columns.is-mobile > .column.is-half { + flex: none; + width: 50%; +} + +.columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; +} + +.columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; +} + +.columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; +} + +.columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; +} + +.columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; +} + +.columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; +} + +.columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; +} + +.columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; +} + +.columns.is-mobile > .column.is-offset-half { + margin-left: 50%; +} + +.columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; +} + +.columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; +} + +.columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; +} + +.columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; +} + +.columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; +} + +.columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; +} + +.columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; +} + +.columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; +} + +.columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; +} + +.columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; +} + +.columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; +} + +.columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; +} + +.columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; +} + +.columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; +} + +.columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; +} + +.columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; +} + +.columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; +} + +.columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; +} + +.columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; +} + +.columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; +} + +.columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; +} + +.columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; +} + +.columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; +} + +.columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; +} + +.columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; +} + +.columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; +} + +.columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; +} + +.columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; +} + +.columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; +} + +.columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; +} + +.columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; +} + +.columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; +} + +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + width: unset; + } + .column.is-full-mobile { + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; + } + .column.is-offset-half-mobile { + margin-left: 50%; + } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; + } + .column.is-0-mobile { + flex: none; + width: 0%; + } + .column.is-offset-0-mobile { + margin-left: 0%; + } + .column.is-1-mobile { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-mobile { + margin-left: 8.33333%; + } + .column.is-2-mobile { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-mobile { + margin-left: 16.66667%; + } + .column.is-3-mobile { + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-left: 25%; + } + .column.is-4-mobile { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-mobile { + margin-left: 33.33333%; + } + .column.is-5-mobile { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-mobile { + margin-left: 41.66667%; + } + .column.is-6-mobile { + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-left: 50%; + } + .column.is-7-mobile { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-mobile { + margin-left: 58.33333%; + } + .column.is-8-mobile { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-mobile { + margin-left: 66.66667%; + } + .column.is-9-mobile { + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-left: 75%; + } + .column.is-10-mobile { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-mobile { + margin-left: 83.33333%; + } + .column.is-11-mobile { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-mobile { + margin-left: 91.66667%; + } + .column.is-12-mobile { + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-left: 100%; + } +} + +@media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; + width: unset; + } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; + } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; + } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; + } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; + } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; + } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; + } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; + } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; + } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-left: 75%; + } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; + } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-left: 50%; + } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-left: 25%; + } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-left: 20%; + } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-left: 40%; + } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-left: 60%; + } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-left: 80%; + } + .column.is-0, .column.is-0-tablet { + flex: none; + width: 0%; + } + .column.is-offset-0, .column.is-offset-0-tablet { + margin-left: 0%; + } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.33333%; + } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-left: 8.33333%; + } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.66667%; + } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-left: 16.66667%; + } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; + } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-left: 25%; + } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.33333%; + } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-left: 33.33333%; + } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.66667%; + } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-left: 41.66667%; + } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; + } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-left: 50%; + } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.33333%; + } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-left: 58.33333%; + } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.66667%; + } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-left: 66.66667%; + } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; + } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-left: 75%; + } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.33333%; + } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-left: 83.33333%; + } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.66667%; + } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-left: 91.66667%; + } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; + } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-left: 100%; + } +} + +@media screen and (max-width: 1023px) { + .column.is-narrow-touch { + flex: none; + width: unset; + } + .column.is-full-touch { + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + flex: none; + width: 50%; + } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-left: 75%; + } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; + } + .column.is-offset-half-touch { + margin-left: 50%; + } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-touch { + margin-left: 25%; + } + .column.is-offset-one-fifth-touch { + margin-left: 20%; + } + .column.is-offset-two-fifths-touch { + margin-left: 40%; + } + .column.is-offset-three-fifths-touch { + margin-left: 60%; + } + .column.is-offset-four-fifths-touch { + margin-left: 80%; + } + .column.is-0-touch { + flex: none; + width: 0%; + } + .column.is-offset-0-touch { + margin-left: 0%; + } + .column.is-1-touch { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-touch { + margin-left: 8.33333%; + } + .column.is-2-touch { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-touch { + margin-left: 16.66667%; + } + .column.is-3-touch { + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-left: 25%; + } + .column.is-4-touch { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-touch { + margin-left: 33.33333%; + } + .column.is-5-touch { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-touch { + margin-left: 41.66667%; + } + .column.is-6-touch { + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-left: 50%; + } + .column.is-7-touch { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-touch { + margin-left: 58.33333%; + } + .column.is-8-touch { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-touch { + margin-left: 66.66667%; + } + .column.is-9-touch { + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-left: 75%; + } + .column.is-10-touch { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-touch { + margin-left: 83.33333%; + } + .column.is-11-touch { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-touch { + margin-left: 91.66667%; + } + .column.is-12-touch { + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-left: 100%; + } +} + +@media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + flex: none; + width: unset; + } + .column.is-full-desktop { + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; + } + .column.is-offset-half-desktop { + margin-left: 50%; + } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; + } + .column.is-0-desktop { + flex: none; + width: 0%; + } + .column.is-offset-0-desktop { + margin-left: 0%; + } + .column.is-1-desktop { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-desktop { + margin-left: 8.33333%; + } + .column.is-2-desktop { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-desktop { + margin-left: 16.66667%; + } + .column.is-3-desktop { + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-left: 25%; + } + .column.is-4-desktop { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-desktop { + margin-left: 33.33333%; + } + .column.is-5-desktop { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-desktop { + margin-left: 41.66667%; + } + .column.is-6-desktop { + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-left: 50%; + } + .column.is-7-desktop { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-desktop { + margin-left: 58.33333%; + } + .column.is-8-desktop { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-desktop { + margin-left: 66.66667%; + } + .column.is-9-desktop { + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-left: 75%; + } + .column.is-10-desktop { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-desktop { + margin-left: 83.33333%; + } + .column.is-11-desktop { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-desktop { + margin-left: 91.66667%; + } + .column.is-12-desktop { + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-left: 100%; + } +} + +@media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + flex: none; + width: unset; + } + .column.is-full-widescreen { + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-left: 50%; + } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; + } + .column.is-0-widescreen { + flex: none; + width: 0%; + } + .column.is-offset-0-widescreen { + margin-left: 0%; + } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; + } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; + } + .column.is-3-widescreen { + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-left: 25%; + } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; + } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; + } + .column.is-6-widescreen { + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-left: 50%; + } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; + } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; + } + .column.is-9-widescreen { + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-left: 75%; + } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; + } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; + } + .column.is-12-widescreen { + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-left: 100%; + } +} + +@media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + flex: none; + width: unset; + } + .column.is-full-fullhd { + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-left: 50%; + } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; + } + .column.is-0-fullhd { + flex: none; + width: 0%; + } + .column.is-offset-0-fullhd { + margin-left: 0%; + } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; + } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; + } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; + } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; + } + .column.is-3-fullhd { + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-left: 25%; + } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; + } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; + } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; + } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; + } + .column.is-6-fullhd { + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-left: 50%; + } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; + } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; + } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; + } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; + } + .column.is-9-fullhd { + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-left: 75%; + } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; + } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; + } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; + } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; + } + .column.is-12-fullhd { + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-left: 100%; + } +} + +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.columns:last-child { + margin-bottom: -0.75rem; +} + +.columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); +} + +.columns.is-centered { + justify-content: center; +} + +.columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; +} + +.columns.is-gapless > .column { + margin: 0; + padding: 0 !important; +} + +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} + +.columns.is-gapless:last-child { + margin-bottom: 0; +} + +.columns.is-mobile { + display: flex; +} + +.columns.is-multiline { + flex-wrap: wrap; +} + +.columns.is-vcentered { + align-items: center; +} + +@media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-desktop { + display: flex; + } +} + +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); +} + +.columns.is-variable > .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); +} + +.columns.is-variable.is-0 { + --columnGap: 0rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; + } +} + +.columns.is-variable.is-1 { + --columnGap: 0.25rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; + } +} + +.columns.is-variable.is-2 { + --columnGap: 0.5rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; + } +} + +.columns.is-variable.is-3 { + --columnGap: 0.75rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; + } +} + +.columns.is-variable.is-4 { + --columnGap: 1rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; + } +} + +.columns.is-variable.is-5 { + --columnGap: 1.25rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; + } +} + +.columns.is-variable.is-6 { + --columnGap: 1.5rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; + } +} + +.columns.is-variable.is-7 { + --columnGap: 1.75rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; + } +} + +.columns.is-variable.is-8 { + --columnGap: 2rem; +} + +@media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; + } +} + +@media screen and (max-width: 1023px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1024px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1216px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; + } +} + +@media screen and (min-width: 1408px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; + } +} + +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: -webkit-min-content; + min-height: -moz-min-content; + min-height: min-content; +} + +.tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; +} + +.tile.is-ancestor:last-child { + margin-bottom: -0.75rem; +} + +.tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; +} + +.tile.is-child { + margin: 0 !important; +} + +.tile.is-parent { + padding: 0.75rem; +} + +.tile.is-vertical { + flex-direction: column; +} + +.tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; +} + +@media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; + } + .tile.is-1 { + flex: none; + width: 8.33333%; + } + .tile.is-2 { + flex: none; + width: 16.66667%; + } + .tile.is-3 { + flex: none; + width: 25%; + } + .tile.is-4 { + flex: none; + width: 33.33333%; + } + .tile.is-5 { + flex: none; + width: 41.66667%; + } + .tile.is-6 { + flex: none; + width: 50%; + } + .tile.is-7 { + flex: none; + width: 58.33333%; + } + .tile.is-8 { + flex: none; + width: 66.66667%; + } + .tile.is-9 { + flex: none; + width: 75%; + } + .tile.is-10 { + flex: none; + width: 83.33333%; + } + .tile.is-11 { + flex: none; + width: 91.66667%; + } + .tile.is-12 { + flex: none; + width: 100%; + } +} + +/* Bulma Helpers */ +.has-text-white { + color: white !important; +} + +a.has-text-white:hover, a.has-text-white:focus { + color: #e6e6e6 !important; +} + +.has-background-white { + background-color: white !important; +} + +.has-text-black { + color: #0a0a0a !important; +} + +a.has-text-black:hover, a.has-text-black:focus { + color: black !important; +} + +.has-background-black { + background-color: #0a0a0a !important; +} + +.has-text-light { + color: whitesmoke !important; +} + +a.has-text-light:hover, a.has-text-light:focus { + color: #dbdbdb !important; +} + +.has-background-light { + background-color: whitesmoke !important; +} + +.has-text-dark { + color: #363636 !important; +} + +a.has-text-dark:hover, a.has-text-dark:focus { + color: #1c1c1c !important; +} + +.has-background-dark { + background-color: #363636 !important; +} + +.has-text-primary { + color: #00d1b2 !important; +} + +a.has-text-primary:hover, a.has-text-primary:focus { + color: #009e86 !important; +} + +.has-background-primary { + background-color: #00d1b2 !important; +} + +.has-text-primary-light { + color: #ebfffc !important; +} + +a.has-text-primary-light:hover, a.has-text-primary-light:focus { + color: #b8fff4 !important; +} + +.has-background-primary-light { + background-color: #ebfffc !important; +} + +.has-text-primary-dark { + color: #00947e !important; +} + +a.has-text-primary-dark:hover, a.has-text-primary-dark:focus { + color: #00c7a9 !important; +} + +.has-background-primary-dark { + background-color: #00947e !important; +} + +.has-text-link { + color: #485fc7 !important; +} + +a.has-text-link:hover, a.has-text-link:focus { + color: #3449a8 !important; +} + +.has-background-link { + background-color: #485fc7 !important; +} + +.has-text-link-light { + color: #eff1fa !important; +} + +a.has-text-link-light:hover, a.has-text-link-light:focus { + color: #c8cfee !important; +} + +.has-background-link-light { + background-color: #eff1fa !important; +} + +.has-text-link-dark { + color: #3850b7 !important; +} + +a.has-text-link-dark:hover, a.has-text-link-dark:focus { + color: #576dcb !important; +} + +.has-background-link-dark { + background-color: #3850b7 !important; +} + +.has-text-info { + color: #3e8ed0 !important; +} + +a.has-text-info:hover, a.has-text-info:focus { + color: #2b74b1 !important; +} + +.has-background-info { + background-color: #3e8ed0 !important; +} + +.has-text-info-light { + color: #eff5fb !important; +} + +a.has-text-info-light:hover, a.has-text-info-light:focus { + color: #c6ddf1 !important; +} + +.has-background-info-light { + background-color: #eff5fb !important; +} + +.has-text-info-dark { + color: #296fa8 !important; +} + +a.has-text-info-dark:hover, a.has-text-info-dark:focus { + color: #368ace !important; +} + +.has-background-info-dark { + background-color: #296fa8 !important; +} + +.has-text-success { + color: #48c78e !important; +} + +a.has-text-success:hover, a.has-text-success:focus { + color: #34a873 !important; +} + +.has-background-success { + background-color: #48c78e !important; +} + +.has-text-success-light { + color: #effaf5 !important; +} + +a.has-text-success-light:hover, a.has-text-success-light:focus { + color: #c8eedd !important; +} + +.has-background-success-light { + background-color: #effaf5 !important; +} + +.has-text-success-dark { + color: #257953 !important; +} + +a.has-text-success-dark:hover, a.has-text-success-dark:focus { + color: #31a06e !important; +} + +.has-background-success-dark { + background-color: #257953 !important; +} + +.has-text-warning { + color: #ffe08a !important; +} + +a.has-text-warning:hover, a.has-text-warning:focus { + color: #ffd257 !important; +} + +.has-background-warning { + background-color: #ffe08a !important; +} + +.has-text-warning-light { + color: #fffaeb !important; +} + +a.has-text-warning-light:hover, a.has-text-warning-light:focus { + color: #ffecb8 !important; +} + +.has-background-warning-light { + background-color: #fffaeb !important; +} + +.has-text-warning-dark { + color: #946c00 !important; +} + +a.has-text-warning-dark:hover, a.has-text-warning-dark:focus { + color: #c79200 !important; +} + +.has-background-warning-dark { + background-color: #946c00 !important; +} + +.has-text-danger { + color: #f14668 !important; +} + +a.has-text-danger:hover, a.has-text-danger:focus { + color: #ee1742 !important; +} + +.has-background-danger { + background-color: #f14668 !important; +} + +.has-text-danger-light { + color: #feecf0 !important; +} + +a.has-text-danger-light:hover, a.has-text-danger-light:focus { + color: #fabdc9 !important; +} + +.has-background-danger-light { + background-color: #feecf0 !important; +} + +.has-text-danger-dark { + color: #cc0f35 !important; +} + +a.has-text-danger-dark:hover, a.has-text-danger-dark:focus { + color: #ee2049 !important; +} + +.has-background-danger-dark { + background-color: #cc0f35 !important; +} + +.has-text-black-bis { + color: #121212 !important; +} + +.has-background-black-bis { + background-color: #121212 !important; +} + +.has-text-black-ter { + color: #242424 !important; +} + +.has-background-black-ter { + background-color: #242424 !important; +} + +.has-text-grey-darker { + color: #363636 !important; +} + +.has-background-grey-darker { + background-color: #363636 !important; +} + +.has-text-grey-dark { + color: #4a4a4a !important; +} + +.has-background-grey-dark { + background-color: #4a4a4a !important; +} + +.has-text-grey { + color: #7a7a7a !important; +} + +.has-background-grey { + background-color: #7a7a7a !important; +} + +.has-text-grey-light { + color: #b5b5b5 !important; +} + +.has-background-grey-light { + background-color: #b5b5b5 !important; +} + +.has-text-grey-lighter { + color: #dbdbdb !important; +} + +.has-background-grey-lighter { + background-color: #dbdbdb !important; +} + +.has-text-white-ter { + color: whitesmoke !important; +} + +.has-background-white-ter { + background-color: whitesmoke !important; +} + +.has-text-white-bis { + color: #fafafa !important; +} + +.has-background-white-bis { + background-color: #fafafa !important; +} + +.is-flex-direction-row { + flex-direction: row !important; +} + +.is-flex-direction-row-reverse { + flex-direction: row-reverse !important; +} + +.is-flex-direction-column { + flex-direction: column !important; +} + +.is-flex-direction-column-reverse { + flex-direction: column-reverse !important; +} + +.is-flex-wrap-nowrap { + flex-wrap: nowrap !important; +} + +.is-flex-wrap-wrap { + flex-wrap: wrap !important; +} + +.is-flex-wrap-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.is-justify-content-flex-start { + justify-content: flex-start !important; +} + +.is-justify-content-flex-end { + justify-content: flex-end !important; +} + +.is-justify-content-center { + justify-content: center !important; +} + +.is-justify-content-space-between { + justify-content: space-between !important; +} + +.is-justify-content-space-around { + justify-content: space-around !important; +} + +.is-justify-content-space-evenly { + justify-content: space-evenly !important; +} + +.is-justify-content-start { + justify-content: start !important; +} + +.is-justify-content-end { + justify-content: end !important; +} + +.is-justify-content-left { + justify-content: left !important; +} + +.is-justify-content-right { + justify-content: right !important; +} + +.is-align-content-flex-start { + align-content: flex-start !important; +} + +.is-align-content-flex-end { + align-content: flex-end !important; +} + +.is-align-content-center { + align-content: center !important; +} + +.is-align-content-space-between { + align-content: space-between !important; +} + +.is-align-content-space-around { + align-content: space-around !important; +} + +.is-align-content-space-evenly { + align-content: space-evenly !important; +} + +.is-align-content-stretch { + align-content: stretch !important; +} + +.is-align-content-start { + align-content: start !important; +} + +.is-align-content-end { + align-content: end !important; +} + +.is-align-content-baseline { + align-content: baseline !important; +} + +.is-align-items-stretch { + align-items: stretch !important; +} + +.is-align-items-flex-start { + align-items: flex-start !important; +} + +.is-align-items-flex-end { + align-items: flex-end !important; +} + +.is-align-items-center { + align-items: center !important; +} + +.is-align-items-baseline { + align-items: baseline !important; +} + +.is-align-items-start { + align-items: start !important; +} + +.is-align-items-end { + align-items: end !important; +} + +.is-align-items-self-start { + align-items: self-start !important; +} + +.is-align-items-self-end { + align-items: self-end !important; +} + +.is-align-self-auto { + align-self: auto !important; +} + +.is-align-self-flex-start { + align-self: flex-start !important; +} + +.is-align-self-flex-end { + align-self: flex-end !important; +} + +.is-align-self-center { + align-self: center !important; +} + +.is-align-self-baseline { + align-self: baseline !important; +} + +.is-align-self-stretch { + align-self: stretch !important; +} + +.is-flex-grow-0 { + flex-grow: 0 !important; +} + +.is-flex-grow-1 { + flex-grow: 1 !important; +} + +.is-flex-grow-2 { + flex-grow: 2 !important; +} + +.is-flex-grow-3 { + flex-grow: 3 !important; +} + +.is-flex-grow-4 { + flex-grow: 4 !important; +} + +.is-flex-grow-5 { + flex-grow: 5 !important; +} + +.is-flex-shrink-0 { + flex-shrink: 0 !important; +} + +.is-flex-shrink-1 { + flex-shrink: 1 !important; +} + +.is-flex-shrink-2 { + flex-shrink: 2 !important; +} + +.is-flex-shrink-3 { + flex-shrink: 3 !important; +} + +.is-flex-shrink-4 { + flex-shrink: 4 !important; +} + +.is-flex-shrink-5 { + flex-shrink: 5 !important; +} + +.is-clearfix::after { + clear: both; + content: " "; + display: table; +} + +.is-pulled-left { + float: left !important; +} + +.is-pulled-right { + float: right !important; +} + +.is-radiusless { + border-radius: 0 !important; +} + +.is-shadowless { + box-shadow: none !important; +} + +.is-clickable { + cursor: pointer !important; + pointer-events: all !important; +} + +.is-clipped { + overflow: hidden !important; +} + +.is-relative { + position: relative !important; +} + +.is-marginless { + margin: 0 !important; +} + +.is-paddingless { + padding: 0 !important; +} + +.m-0 { + margin: 0 !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mr-0 { + margin-right: 0 !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.ml-0 { + margin-left: 0 !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mr-1 { + margin-right: 0.25rem !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1 { + margin-left: 0.25rem !important; +} + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mr-2 { + margin-right: 0.5rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2 { + margin-left: 0.5rem !important; +} + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.m-3 { + margin: 0.75rem !important; +} + +.mt-3 { + margin-top: 0.75rem !important; +} + +.mr-3 { + margin-right: 0.75rem !important; +} + +.mb-3 { + margin-bottom: 0.75rem !important; +} + +.ml-3 { + margin-left: 0.75rem !important; +} + +.mx-3 { + margin-left: 0.75rem !important; + margin-right: 0.75rem !important; +} + +.my-3 { + margin-top: 0.75rem !important; + margin-bottom: 0.75rem !important; +} + +.m-4 { + margin: 1rem !important; +} + +.mt-4 { + margin-top: 1rem !important; +} + +.mr-4 { + margin-right: 1rem !important; +} + +.mb-4 { + margin-bottom: 1rem !important; +} + +.ml-4 { + margin-left: 1rem !important; +} + +.mx-4 { + margin-left: 1rem !important; + margin-right: 1rem !important; +} + +.my-4 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.m-5 { + margin: 1.5rem !important; +} + +.mt-5 { + margin-top: 1.5rem !important; +} + +.mr-5 { + margin-right: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 1.5rem !important; +} + +.ml-5 { + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; +} + +.my-5 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.m-6 { + margin: 3rem !important; +} + +.mt-6 { + margin-top: 3rem !important; +} + +.mr-6 { + margin-right: 3rem !important; +} + +.mb-6 { + margin-bottom: 3rem !important; +} + +.ml-6 { + margin-left: 3rem !important; +} + +.mx-6 { + margin-left: 3rem !important; + margin-right: 3rem !important; +} + +.my-6 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.mr-auto { + margin-right: auto !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ml-auto { + margin-left: auto !important; +} + +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pr-0 { + padding-right: 0 !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pl-0 { + padding-left: 0 !important; +} + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pr-1 { + padding-right: 0.25rem !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1 { + padding-left: 0.25rem !important; +} + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pr-2 { + padding-right: 0.5rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2 { + padding-left: 0.5rem !important; +} + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.p-3 { + padding: 0.75rem !important; +} + +.pt-3 { + padding-top: 0.75rem !important; +} + +.pr-3 { + padding-right: 0.75rem !important; +} + +.pb-3 { + padding-bottom: 0.75rem !important; +} + +.pl-3 { + padding-left: 0.75rem !important; +} + +.px-3 { + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; +} + +.py-3 { + padding-top: 0.75rem !important; + padding-bottom: 0.75rem !important; +} + +.p-4 { + padding: 1rem !important; +} + +.pt-4 { + padding-top: 1rem !important; +} + +.pr-4 { + padding-right: 1rem !important; +} + +.pb-4 { + padding-bottom: 1rem !important; +} + +.pl-4 { + padding-left: 1rem !important; +} + +.px-4 { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +.py-4 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.p-5 { + padding: 1.5rem !important; +} + +.pt-5 { + padding-top: 1.5rem !important; +} + +.pr-5 { + padding-right: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 1.5rem !important; +} + +.pl-5 { + padding-left: 1.5rem !important; +} + +.px-5 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; +} + +.py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.p-6 { + padding: 3rem !important; +} + +.pt-6 { + padding-top: 3rem !important; +} + +.pr-6 { + padding-right: 3rem !important; +} + +.pb-6 { + padding-bottom: 3rem !important; +} + +.pl-6 { + padding-left: 3rem !important; +} + +.px-6 { + padding-left: 3rem !important; + padding-right: 3rem !important; +} + +.py-6 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.p-auto { + padding: auto !important; +} + +.pt-auto { + padding-top: auto !important; +} + +.pr-auto { + padding-right: auto !important; +} + +.pb-auto { + padding-bottom: auto !important; +} + +.pl-auto { + padding-left: auto !important; +} + +.px-auto { + padding-left: auto !important; + padding-right: auto !important; +} + +.py-auto { + padding-top: auto !important; + padding-bottom: auto !important; +} + +.is-size-1 { + font-size: 3rem !important; +} + +.is-size-2 { + font-size: 2.5rem !important; +} + +.is-size-3 { + font-size: 2rem !important; +} + +.is-size-4 { + font-size: 1.5rem !important; +} + +.is-size-5 { + font-size: 1.25rem !important; +} + +.is-size-6 { + font-size: 1rem !important; +} + +.is-size-7 { + font-size: 0.75rem !important; +} + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; + } + .is-size-2-mobile { + font-size: 2.5rem !important; + } + .is-size-3-mobile { + font-size: 2rem !important; + } + .is-size-4-mobile { + font-size: 1.5rem !important; + } + .is-size-5-mobile { + font-size: 1.25rem !important; + } + .is-size-6-mobile { + font-size: 1rem !important; + } + .is-size-7-mobile { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; + } + .is-size-2-tablet { + font-size: 2.5rem !important; + } + .is-size-3-tablet { + font-size: 2rem !important; + } + .is-size-4-tablet { + font-size: 1.5rem !important; + } + .is-size-5-tablet { + font-size: 1.25rem !important; + } + .is-size-6-tablet { + font-size: 1rem !important; + } + .is-size-7-tablet { + font-size: 0.75rem !important; + } +} + +@media screen and (max-width: 1023px) { + .is-size-1-touch { + font-size: 3rem !important; + } + .is-size-2-touch { + font-size: 2.5rem !important; + } + .is-size-3-touch { + font-size: 2rem !important; + } + .is-size-4-touch { + font-size: 1.5rem !important; + } + .is-size-5-touch { + font-size: 1.25rem !important; + } + .is-size-6-touch { + font-size: 1rem !important; + } + .is-size-7-touch { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1024px) { + .is-size-1-desktop { + font-size: 3rem !important; + } + .is-size-2-desktop { + font-size: 2.5rem !important; + } + .is-size-3-desktop { + font-size: 2rem !important; + } + .is-size-4-desktop { + font-size: 1.5rem !important; + } + .is-size-5-desktop { + font-size: 1.25rem !important; + } + .is-size-6-desktop { + font-size: 1rem !important; + } + .is-size-7-desktop { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1216px) { + .is-size-1-widescreen { + font-size: 3rem !important; + } + .is-size-2-widescreen { + font-size: 2.5rem !important; + } + .is-size-3-widescreen { + font-size: 2rem !important; + } + .is-size-4-widescreen { + font-size: 1.5rem !important; + } + .is-size-5-widescreen { + font-size: 1.25rem !important; + } + .is-size-6-widescreen { + font-size: 1rem !important; + } + .is-size-7-widescreen { + font-size: 0.75rem !important; + } +} + +@media screen and (min-width: 1408px) { + .is-size-1-fullhd { + font-size: 3rem !important; + } + .is-size-2-fullhd { + font-size: 2.5rem !important; + } + .is-size-3-fullhd { + font-size: 2rem !important; + } + .is-size-4-fullhd { + font-size: 1.5rem !important; + } + .is-size-5-fullhd { + font-size: 1.25rem !important; + } + .is-size-6-fullhd { + font-size: 1rem !important; + } + .is-size-7-fullhd { + font-size: 0.75rem !important; + } +} + +.has-text-centered { + text-align: center !important; +} + +.has-text-justified { + text-align: justify !important; +} + +.has-text-left { + text-align: left !important; +} + +.has-text-right { + text-align: right !important; +} + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-centered-tablet-only { + text-align: center !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-centered-touch { + text-align: center !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-centered-desktop { + text-align: center !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-centered-desktop-only { + text-align: center !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-centered-widescreen { + text-align: center !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-centered-widescreen-only { + text-align: center !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-centered-fullhd { + text-align: center !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-justified-tablet-only { + text-align: justify !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-justified-touch { + text-align: justify !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-justified-desktop { + text-align: justify !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-justified-desktop-only { + text-align: justify !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-justified-widescreen { + text-align: justify !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-justified-widescreen-only { + text-align: justify !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-justified-fullhd { + text-align: justify !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-left-tablet-only { + text-align: left !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-left-touch { + text-align: left !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-left-desktop { + text-align: left !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-left-desktop-only { + text-align: left !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-left-widescreen { + text-align: left !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-left-widescreen-only { + text-align: left !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-left-fullhd { + text-align: left !important; + } +} + +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; + } +} + +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-right-tablet-only { + text-align: right !important; + } +} + +@media screen and (max-width: 1023px) { + .has-text-right-touch { + text-align: right !important; + } +} + +@media screen and (min-width: 1024px) { + .has-text-right-desktop { + text-align: right !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-right-desktop-only { + text-align: right !important; + } +} + +@media screen and (min-width: 1216px) { + .has-text-right-widescreen { + text-align: right !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-right-widescreen-only { + text-align: right !important; + } +} + +@media screen and (min-width: 1408px) { + .has-text-right-fullhd { + text-align: right !important; + } +} + +.is-capitalized { + text-transform: capitalize !important; +} + +.is-lowercase { + text-transform: lowercase !important; +} + +.is-uppercase { + text-transform: uppercase !important; +} + +.is-italic { + font-style: italic !important; +} + +.is-underlined { + text-decoration: underline !important; +} + +.has-text-weight-light { + font-weight: 300 !important; +} + +.has-text-weight-normal { + font-weight: 400 !important; +} + +.has-text-weight-medium { + font-weight: 500 !important; +} + +.has-text-weight-semibold { + font-weight: 600 !important; +} + +.has-text-weight-bold { + font-weight: 700 !important; +} + +.is-family-primary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-secondary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-sans-serif { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-monospace { + font-family: monospace !important; +} + +.is-family-code { + font-family: monospace !important; +} + +.is-block { + display: block !important; +} + +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; + } +} + +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-block-tablet-only { + display: block !important; + } +} + +@media screen and (max-width: 1023px) { + .is-block-touch { + display: block !important; + } +} + +@media screen and (min-width: 1024px) { + .is-block-desktop { + display: block !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-block-desktop-only { + display: block !important; + } +} + +@media screen and (min-width: 1216px) { + .is-block-widescreen { + display: block !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-block-widescreen-only { + display: block !important; + } +} + +@media screen and (min-width: 1408px) { + .is-block-fullhd { + display: block !important; + } +} + +.is-flex { + display: flex !important; +} + +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; + } +} + +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-flex-tablet-only { + display: flex !important; + } +} + +@media screen and (max-width: 1023px) { + .is-flex-touch { + display: flex !important; + } +} + +@media screen and (min-width: 1024px) { + .is-flex-desktop { + display: flex !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-flex-desktop-only { + display: flex !important; + } +} + +@media screen and (min-width: 1216px) { + .is-flex-widescreen { + display: flex !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-flex-widescreen-only { + display: flex !important; + } +} + +@media screen and (min-width: 1408px) { + .is-flex-fullhd { + display: flex !important; + } +} + +.is-inline { + display: inline !important; +} + +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-tablet-only { + display: inline !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-touch { + display: inline !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-desktop { + display: inline !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-desktop-only { + display: inline !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-widescreen { + display: inline !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-widescreen-only { + display: inline !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-fullhd { + display: inline !important; + } +} + +.is-inline-block { + display: inline-block !important; +} + +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-block-tablet-only { + display: inline-block !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-block-touch { + display: inline-block !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-block-desktop { + display: inline-block !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-block-desktop-only { + display: inline-block !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-block-widescreen { + display: inline-block !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-block-widescreen-only { + display: inline-block !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-block-fullhd { + display: inline-block !important; + } +} + +.is-inline-flex { + display: inline-flex !important; +} + +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; + } +} + +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; + } +} + +@media screen and (max-width: 1023px) { + .is-inline-flex-touch { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1024px) { + .is-inline-flex-desktop { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1216px) { + .is-inline-flex-widescreen { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; + } +} + +@media screen and (min-width: 1408px) { + .is-inline-flex-fullhd { + display: inline-flex !important; + } +} + +.is-hidden { + display: none !important; +} + +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; +} + +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; + } +} + +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-hidden-tablet-only { + display: none !important; + } +} + +@media screen and (max-width: 1023px) { + .is-hidden-touch { + display: none !important; + } +} + +@media screen and (min-width: 1024px) { + .is-hidden-desktop { + display: none !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-hidden-desktop-only { + display: none !important; + } +} + +@media screen and (min-width: 1216px) { + .is-hidden-widescreen { + display: none !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-hidden-widescreen-only { + display: none !important; + } +} + +@media screen and (min-width: 1408px) { + .is-hidden-fullhd { + display: none !important; + } +} + +.is-invisible { + visibility: hidden !important; +} + +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; + } +} + +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; + } +} + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-invisible-tablet-only { + visibility: hidden !important; + } +} + +@media screen and (max-width: 1023px) { + .is-invisible-touch { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1024px) { + .is-invisible-desktop { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-invisible-desktop-only { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1216px) { + .is-invisible-widescreen { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-invisible-widescreen-only { + visibility: hidden !important; + } +} + +@media screen and (min-width: 1408px) { + .is-invisible-fullhd { + visibility: hidden !important; + } +} + +/* Bulma Layout */ +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.hero .navbar { + background: none; +} + +.hero .tabs ul { + border-bottom: none; +} + +.hero.is-white { + background-color: white; + color: #0a0a0a; +} + +.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-white strong { + color: inherit; +} + +.hero.is-white .title { + color: #0a0a0a; +} + +.hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); +} + +.hero.is-white .subtitle a:not(.button), +.hero.is-white .subtitle strong { + color: #0a0a0a; +} + +@media screen and (max-width: 1023px) { + .hero.is-white .navbar-menu { + background-color: white; + } +} + +.hero.is-white .navbar-item, +.hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); +} + +.hero.is-white a.navbar-item:hover, .hero.is-white a.navbar-item.is-active, +.hero.is-white .navbar-link:hover, +.hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; +} + +.hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; +} + +.hero.is-white .tabs a:hover { + opacity: 1; +} + +.hero.is-white .tabs li.is-active a { + color: white !important; + opacity: 1; +} + +.hero.is-white .tabs.is-boxed a, .hero.is-white .tabs.is-toggle a { + color: #0a0a0a; +} + +.hero.is-white .tabs.is-boxed a:hover, .hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-white .tabs.is-boxed li.is-active a, .hero.is-white .tabs.is-boxed li.is-active a:hover, .hero.is-white .tabs.is-toggle li.is-active a, .hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; +} + +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); + } +} + +.hero.is-black { + background-color: #0a0a0a; + color: white; +} + +.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-black strong { + color: inherit; +} + +.hero.is-black .title { + color: white; +} + +.hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-black .subtitle a:not(.button), +.hero.is-black .subtitle strong { + color: white; +} + +@media screen and (max-width: 1023px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; + } +} + +.hero.is-black .navbar-item, +.hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-black a.navbar-item:hover, .hero.is-black a.navbar-item.is-active, +.hero.is-black .navbar-link:hover, +.hero.is-black .navbar-link.is-active { + background-color: black; + color: white; +} + +.hero.is-black .tabs a { + color: white; + opacity: 0.9; +} + +.hero.is-black .tabs a:hover { + opacity: 1; +} + +.hero.is-black .tabs li.is-active a { + color: #0a0a0a !important; + opacity: 1; +} + +.hero.is-black .tabs.is-boxed a, .hero.is-black .tabs.is-toggle a { + color: white; +} + +.hero.is-black .tabs.is-boxed a:hover, .hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-black .tabs.is-boxed li.is-active a, .hero.is-black .tabs.is-boxed li.is-active a:hover, .hero.is-black .tabs.is-toggle li.is-active a, .hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; +} + +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); + } +} + +.hero.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-light strong { + color: inherit; +} + +.hero.is-light .title { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .subtitle { + color: rgba(0, 0, 0, 0.9); +} + +.hero.is-light .subtitle a:not(.button), +.hero.is-light .subtitle strong { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (max-width: 1023px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; + } +} + +.hero.is-light .navbar-item, +.hero.is-light .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light a.navbar-item:hover, .hero.is-light a.navbar-item.is-active, +.hero.is-light .navbar-link:hover, +.hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; +} + +.hero.is-light .tabs a:hover { + opacity: 1; +} + +.hero.is-light .tabs li.is-active a { + color: whitesmoke !important; + opacity: 1; +} + +.hero.is-light .tabs.is-boxed a, .hero.is-light .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-light .tabs.is-boxed a:hover, .hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-light .tabs.is-boxed li.is-active a, .hero.is-light .tabs.is-boxed li.is-active a:hover, .hero.is-light .tabs.is-toggle li.is-active a, .hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; +} + +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); + } +} + +.hero.is-dark { + background-color: #363636; + color: #fff; +} + +.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-dark strong { + color: inherit; +} + +.hero.is-dark .title { + color: #fff; +} + +.hero.is-dark .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-dark .subtitle a:not(.button), +.hero.is-dark .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-dark .navbar-menu { + background-color: #363636; + } +} + +.hero.is-dark .navbar-item, +.hero.is-dark .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-dark a.navbar-item:hover, .hero.is-dark a.navbar-item.is-active, +.hero.is-dark .navbar-link:hover, +.hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; +} + +.hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-dark .tabs a:hover { + opacity: 1; +} + +.hero.is-dark .tabs li.is-active a { + color: #363636 !important; + opacity: 1; +} + +.hero.is-dark .tabs.is-boxed a, .hero.is-dark .tabs.is-toggle a { + color: #fff; +} + +.hero.is-dark .tabs.is-boxed a:hover, .hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-dark .tabs.is-boxed li.is-active a, .hero.is-dark .tabs.is-boxed li.is-active a:hover, .hero.is-dark .tabs.is-toggle li.is-active a, .hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; +} + +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); + } +} + +.hero.is-primary { + background-color: #00d1b2; + color: #fff; +} + +.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-primary strong { + color: inherit; +} + +.hero.is-primary .title { + color: #fff; +} + +.hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-primary .subtitle a:not(.button), +.hero.is-primary .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; + } +} + +.hero.is-primary .navbar-item, +.hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-primary a.navbar-item:hover, .hero.is-primary a.navbar-item.is-active, +.hero.is-primary .navbar-link:hover, +.hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; +} + +.hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-primary .tabs a:hover { + opacity: 1; +} + +.hero.is-primary .tabs li.is-active a { + color: #00d1b2 !important; + opacity: 1; +} + +.hero.is-primary .tabs.is-boxed a, .hero.is-primary .tabs.is-toggle a { + color: #fff; +} + +.hero.is-primary .tabs.is-boxed a:hover, .hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-primary .tabs.is-boxed li.is-active a, .hero.is-primary .tabs.is-boxed li.is-active a:hover, .hero.is-primary .tabs.is-toggle li.is-active a, .hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; +} + +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); + } +} + +.hero.is-link { + background-color: #485fc7; + color: #fff; +} + +.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-link strong { + color: inherit; +} + +.hero.is-link .title { + color: #fff; +} + +.hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-link .subtitle a:not(.button), +.hero.is-link .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-link .navbar-menu { + background-color: #485fc7; + } +} + +.hero.is-link .navbar-item, +.hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-link a.navbar-item:hover, .hero.is-link a.navbar-item.is-active, +.hero.is-link .navbar-link:hover, +.hero.is-link .navbar-link.is-active { + background-color: #3a51bb; + color: #fff; +} + +.hero.is-link .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-link .tabs a:hover { + opacity: 1; +} + +.hero.is-link .tabs li.is-active a { + color: #485fc7 !important; + opacity: 1; +} + +.hero.is-link .tabs.is-boxed a, .hero.is-link .tabs.is-toggle a { + color: #fff; +} + +.hero.is-link .tabs.is-boxed a:hover, .hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-link .tabs.is-boxed li.is-active a, .hero.is-link .tabs.is-boxed li.is-active a:hover, .hero.is-link .tabs.is-toggle li.is-active a, .hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #485fc7; +} + +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, #2959b3 0%, #485fc7 71%, #5658d2 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #2959b3 0%, #485fc7 71%, #5658d2 100%); + } +} + +.hero.is-info { + background-color: #3e8ed0; + color: #fff; +} + +.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-info strong { + color: inherit; +} + +.hero.is-info .title { + color: #fff; +} + +.hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-info .subtitle a:not(.button), +.hero.is-info .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-info .navbar-menu { + background-color: #3e8ed0; + } +} + +.hero.is-info .navbar-item, +.hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-info a.navbar-item:hover, .hero.is-info a.navbar-item.is-active, +.hero.is-info .navbar-link:hover, +.hero.is-info .navbar-link.is-active { + background-color: #3082c5; + color: #fff; +} + +.hero.is-info .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-info .tabs a:hover { + opacity: 1; +} + +.hero.is-info .tabs li.is-active a { + color: #3e8ed0 !important; + opacity: 1; +} + +.hero.is-info .tabs.is-boxed a, .hero.is-info .tabs.is-toggle a { + color: #fff; +} + +.hero.is-info .tabs.is-boxed a:hover, .hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-info .tabs.is-boxed li.is-active a, .hero.is-info .tabs.is-boxed li.is-active a:hover, .hero.is-info .tabs.is-toggle li.is-active a, .hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3e8ed0; +} + +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, #208fbc 0%, #3e8ed0 71%, #4d83db 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #208fbc 0%, #3e8ed0 71%, #4d83db 100%); + } +} + +.hero.is-success { + background-color: #48c78e; + color: #fff; +} + +.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-success strong { + color: inherit; +} + +.hero.is-success .title { + color: #fff; +} + +.hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-success .subtitle a:not(.button), +.hero.is-success .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-success .navbar-menu { + background-color: #48c78e; + } +} + +.hero.is-success .navbar-item, +.hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-success a.navbar-item:hover, .hero.is-success a.navbar-item.is-active, +.hero.is-success .navbar-link:hover, +.hero.is-success .navbar-link.is-active { + background-color: #3abb81; + color: #fff; +} + +.hero.is-success .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-success .tabs a:hover { + opacity: 1; +} + +.hero.is-success .tabs li.is-active a { + color: #48c78e !important; + opacity: 1; +} + +.hero.is-success .tabs.is-boxed a, .hero.is-success .tabs.is-toggle a { + color: #fff; +} + +.hero.is-success .tabs.is-boxed a:hover, .hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-success .tabs.is-boxed li.is-active a, .hero.is-success .tabs.is-boxed li.is-active a:hover, .hero.is-success .tabs.is-toggle li.is-active a, .hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #48c78e; +} + +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, #29b35e 0%, #48c78e 71%, #56d2af 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #29b35e 0%, #48c78e 71%, #56d2af 100%); + } +} + +.hero.is-warning { + background-color: #ffe08a; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-warning strong { + color: inherit; +} + +.hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); +} + +.hero.is-warning .subtitle a:not(.button), +.hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); +} + +@media screen and (max-width: 1023px) { + .hero.is-warning .navbar-menu { + background-color: #ffe08a; + } +} + +.hero.is-warning .navbar-item, +.hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning a.navbar-item:hover, .hero.is-warning a.navbar-item.is-active, +.hero.is-warning .navbar-link:hover, +.hero.is-warning .navbar-link.is-active { + background-color: #ffd970; + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; +} + +.hero.is-warning .tabs a:hover { + opacity: 1; +} + +.hero.is-warning .tabs li.is-active a { + color: #ffe08a !important; + opacity: 1; +} + +.hero.is-warning .tabs.is-boxed a, .hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); +} + +.hero.is-warning .tabs.is-boxed a:hover, .hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-warning .tabs.is-boxed li.is-active a, .hero.is-warning .tabs.is-boxed li.is-active a:hover, .hero.is-warning .tabs.is-toggle li.is-active a, .hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffe08a; +} + +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffb657 0%, #ffe08a 71%, #fff6a3 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffb657 0%, #ffe08a 71%, #fff6a3 100%); + } +} + +.hero.is-danger { + background-color: #f14668; + color: #fff; +} + +.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), +.hero.is-danger strong { + color: inherit; +} + +.hero.is-danger .title { + color: #fff; +} + +.hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); +} + +.hero.is-danger .subtitle a:not(.button), +.hero.is-danger .subtitle strong { + color: #fff; +} + +@media screen and (max-width: 1023px) { + .hero.is-danger .navbar-menu { + background-color: #f14668; + } +} + +.hero.is-danger .navbar-item, +.hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); +} + +.hero.is-danger a.navbar-item:hover, .hero.is-danger a.navbar-item.is-active, +.hero.is-danger .navbar-link:hover, +.hero.is-danger .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; +} + +.hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; +} + +.hero.is-danger .tabs a:hover { + opacity: 1; +} + +.hero.is-danger .tabs li.is-active a { + color: #f14668 !important; + opacity: 1; +} + +.hero.is-danger .tabs.is-boxed a, .hero.is-danger .tabs.is-toggle a { + color: #fff; +} + +.hero.is-danger .tabs.is-boxed a:hover, .hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); +} + +.hero.is-danger .tabs.is-boxed li.is-active a, .hero.is-danger .tabs.is-boxed li.is-active a:hover, .hero.is-danger .tabs.is-toggle li.is-active a, .hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #f14668; +} + +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); +} + +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); + } +} + +.hero.is-small .hero-body { + padding: 1.5rem; +} + +@media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding: 9rem 4.5rem; + } +} + +@media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding: 18rem 6rem; + } +} + +.hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; +} + +.hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; +} + +.hero.is-halfheight { + min-height: 50vh; +} + +.hero.is-fullheight { + min-height: 100vh; +} + +.hero-video { + overflow: hidden; +} + +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); +} + +.hero-video.is-transparent { + opacity: 0.3; +} + +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} + +.hero-buttons { + margin-top: 1.5rem; +} + +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} + +@media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; + } +} + +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; +} + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; +} + +@media screen and (min-width: 769px), print { + .hero-body { + padding: 3rem 3rem; + } +} + +.section { + padding: 3rem 1.5rem; +} + +@media screen and (min-width: 1024px) { + .section { + padding: 3rem 3rem; + } + .section.is-medium { + padding: 9rem 4.5rem; + } + .section.is-large { + padding: 18rem 6rem; + } +} + +.footer { + background-color: #fafafa; + padding: 3rem 1.5rem 6rem; +} +/*# sourceMappingURL=bulma.css.map */ \ No newline at end of file diff --git a/templ/examples/counter/assets/css/bulma.css.map b/templ/examples/counter/assets/css/bulma.css.map new file mode 100644 index 0000000..dbe97a3 --- /dev/null +++ b/templ/examples/counter/assets/css/bulma.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../bulma.sass","../sass/utilities/_all.sass","../sass/utilities/extends.sass","../sass/utilities/controls.sass","../sass/utilities/initial-variables.sass","bulma.css","../sass/utilities/mixins.sass","../sass/base/_all.sass","../sass/base/minireset.sass","../sass/base/generic.sass","../sass/utilities/derived-variables.sass","../sass/base/animations.sass","../sass/elements/_all.sass","../sass/elements/box.sass","../sass/elements/button.sass","../sass/utilities/functions.sass","../sass/elements/container.sass","../sass/elements/content.sass","../sass/elements/icon.sass","../sass/elements/image.sass","../sass/elements/notification.sass","../sass/elements/progress.sass","../sass/elements/table.sass","../sass/elements/tag.sass","../sass/elements/title.sass","../sass/elements/other.sass","../sass/form/_all.sass","../sass/form/shared.sass","../sass/form/input-textarea.sass","../sass/form/checkbox-radio.sass","../sass/form/select.sass","../sass/form/file.sass","../sass/form/tools.sass","../sass/components/_all.sass","../sass/components/breadcrumb.sass","../sass/components/card.sass","../sass/components/dropdown.sass","../sass/components/level.sass","../sass/components/media.sass","../sass/components/menu.sass","../sass/components/message.sass","../sass/components/modal.sass","../sass/components/navbar.sass","../sass/components/pagination.sass","../sass/components/panel.sass","../sass/components/tabs.sass","../sass/grid/_all.sass","../sass/grid/columns.sass","../sass/grid/tiles.sass","../sass/helpers/_all.sass","../sass/helpers/color.sass","../sass/helpers/flexbox.sass","../sass/helpers/float.sass","../sass/helpers/other.sass","../sass/helpers/overflow.sass","../sass/helpers/position.sass","../sass/helpers/spacing.sass","../sass/helpers/typography.sass","../sass/helpers/visibility.sass","../sass/layout/_all.sass","../sass/layout/hero.sass","../sass/layout/section.sass","../sass/layout/footer.sass"],"names":[],"mappings":"AACA,6DAAA;ACDA,oBAAA;ACEA;;;;;ECYE,qBAAqB;EACrB,wBAAwB;EACxB,mBAAmB;EACnB,6BAA+C;EAC/C,kBCoDU;EDnDV,gBAAgB;EAChB,oBAAoB;EACpB,eCgBW;EDfX,aAfoB;EAgBpB,2BAA2B;EAC3B,gBAhBuB;EAiBvB,iCAf+D;EAgB/D,gCAfkE;EAgBlE,iCAhBkE;EAiBlE,8BAlB+D;EAmB/D,kBAAkB;EAClB,mBAAmB;AENrB;;AFQE;;;;;;;;;;;;;;;;;EAIE,aAAa;AEQjB;;AFPE;;;;;;;;;;;;;;;;EAEE,mBAAmB;AEwBvB;;AH1DA;;;;EI4LE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;AD3HnB;;AHlEA;EIgME,6BAD8B;EAE9B,kBAAkB;EAClB,eAAe;EACf,aAAa;EACb,YAAY;EACZ,cAAc;EACd,eAAe;EACf,qBAAqB;EACrB,oBAAoB;EACpB,kBAAkB;EAClB,QAAQ;EACR,yBAAyB;EACzB,wBAAwB;EACxB,cAAc;AD1HhB;;AC6HE;;EACE,qBFzKkB;ACgDtB;;AHlFA;EImLE,2BAA2B;EAC3B,yBAAyB;EACzB,sBAAsB;EACtB,qBAAqB;EACrB,iBAAiB;EAwBjB,qBAAqB;EACrB,wBAAwB;EACxB,uCF7N2B;EE8N3B,YAAY;EACZ,qBFzJqB;EE0JrB,eAAe;EACf,oBAAoB;EACpB,qBAAqB;EACrB,YAAY;EACZ,cAAc;EACd,YAAY;EACZ,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,aAAa;EACb,kBAAkB;EAClB,mBAAmB;EACnB,WAAW;ADpHb;;ACqHE;EAEE,uBFpO2B;EEqO3B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;ADnHnC;;ACoHE;EACE,WAAW;EACX,UAAU;ADjHd;;ACkHE;EACE,WAAW;EACX,UAAU;AD/Gd;;ACgHE;EAEE,uCFjQyB;ACmJ7B;;AC+GE;EACE,uCFnQyB;ACuJ7B;;AC8GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;AD3Gf;;AC4GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADzGf;;AC0GE;EACE,YAAY;EACZ,gBAAgB;EAChB,eAAe;EACf,gBAAgB;EAChB,eAAe;EACf,WAAW;ADvGf;;AHnKA;EI6QE,mDAA2C;UAA3C,2CAA2C;EAC3C,yBFrR4B;EEsR5B,qBFxNqB;EEyNrB,+BAA+B;EAC/B,6BAA6B;EAC7B,WAAW;EACX,cAAc;EACd,WAAW;EACX,kBAAkB;EAClB,UAAU;ADtGZ;;AH7KA;;;;;;;;;;;;;;;;;EIsRE,SADuB;EAEvB,OAFuB;EAGvB,kBAAkB;EAClB,QAJuB;EAKvB,MALuB;ADhFzB;;AHlMA;EIqDE,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,mBAAmB;EACnB,oBAAoB;EACpB,cAAc;EACd,SAAS;EACT,UAAU;ADiJZ;;AEtOA,eAAA;ACAA,0EAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;EAuBE,SAAS;EACT,UAAU;AHyOZ;;AGtOA;;;;;;EAME,eAAe;EACf,mBAAmB;AHyOrB;;AGtOA;EACE,gBAAgB;AHyOlB;;AGtOA;;;;EAIE,SAAS;AHyOX;;AGtOA;EACE,sBAAsB;AHyOxB;;AGvOA;EAII,mBAAmB;AHuOvB;;AGpOA;;EAEE,YAAY;EACZ,eAAe;AHuOjB;;AGpOA;EACE,SAAS;AHuOX;;AGpOA;EACE,yBAAyB;EACzB,iBAAiB;AHuOnB;;AGrOA;;EAEE,UAAU;AHwOZ;;AG1OA;;EAII,mBAAmB;AH2OvB;;AGvQA;EChBE,uBLnB6B;EKoB7B,eAhCc;EAiCd,kCAAkC;EAClC,mCAAmC;EACnC,gBAlCoB;EAmCpB,kBAhCsB;EAiCtB,kBAhCsB;EAiCtB,kCApCiC;EAqCjC,8BAAsB;KAAtB,2BAAsB;UAAtB,sBAAsB;AJ2RxB;;AIzRA;;;;;;;EAOE,cAAc;AJ4RhB;;AI1RA;;;;;;EAME,oLL/ByL;AC4T3L;;AI3RA;;EAEE,6BAA6B;EAC7B,4BAA4B;EAC5B,sBLpC0B;ACkU5B;;AI5RA;EACE,cL7D4B;EK8D5B,cA1DkB;EA2DlB,gBL7BiB;EK8BjB,gBA1DoB;AJyVtB;;AI3RA;EACE,cLtDgC;EKuDhC,eAAe;EACf,qBAAqB;AJ8RvB;;AIjSA;EAKI,mBAAmB;AJgSvB;;AIrSA;EAOI,cL5E0B;AC8W9B;;AIhSA;EACE,4BLxE4B;EKyE5B,cCnBsB;EDoBtB,kBArEiB;EAsEjB,mBAvEkB;EAwElB,4BAzEgC;AJ4WlC;;AIjSA;EACE,4BL/E4B;EKgF5B,YAAY;EACZ,cAAc;EACd,WAxEa;EAyEb,gBAxEkB;AJ4WpB;;AIlSA;EACE,YAAY;EACZ,eAAe;AJqSjB;;AInSA;;EAEE,wBAAwB;AJsS1B;;AIpSA;EACE,kBAvFuB;AJ8XzB;;AIrSA;EACE,mBAAmB;EACnB,oBAAoB;AJwStB;;AItSA;EACE,cL5G4B;EK6G5B,gBLvEe;ACgXjB;;AIrSA;EACE,YAAY;AJwSd;;AItSA;EHvDE,iCAAiC;EGyDjC,4BL/G4B;EKgH5B,cLtH4B;EKuH5B,kBAjGqB;EAkGrB,gBAAgB;EAChB,uBAlG0B;EAmG1B,gBAAgB;EAChB,iBAAiB;AJySnB;;AIjTA;EAUI,6BAA6B;EAC7B,mBAAmB;EACnB,cAvGoB;EAwGpB,UAAU;AJ2Sd;;AIzSA;;EAGI,mBAAmB;AJ2SvB;;AI9SA;;EAKM,mBAAmB;AJ8SzB;;AInTA;EAOI,cL1I0B;AC0b9B;;AMhcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AMzcA;EACE;IACE,uBAAuB;ENmczB;EMlcA;IACE,yBAAyB;ENoc3B;AACF;;AOzcA,mBAAA;ACWA;EAEE,uBTE6B;ESD7B,kBTyDgB;ESxDhB,0FTb2B;ESc3B,cTT4B;ESU5B,cAAc;EACd,gBAZmB;AR6crB;;AQ/bA;EAGI,yETD8B;ACiclC;;AQncA;EAKI,oETH8B;ACqclC;;AS/ZA;EAGE,uBVhD6B;EUiD7B,qBVtD4B;EUuD5B,iBX5DwB;EW6DxB,cV5D4B;EU6D5B,eAAe;EAGf,uBAAuB;EACvB,iCA7D6D;EA8D7D,iBA7D6B;EA8D7B,kBA9D6B;EA+D7B,8BAhE6D;EAiE7D,kBAAkB;EAClB,mBAAmB;AT8ZrB;;AS9aA;EAkBI,cAAc;ATgalB;;ASlbA;EAwBM,aAAa;EACb,YAAY;AT8ZlB;;ASvbA;ERwHI,+BQ7FsG;ER6FtG,oBQ5FmE;ATgavE;;AS5bA;ERwHI,mBQ1FmE;ER0FnE,gCQzFsG;ATka1G;;ASjcA;EAiCM,+BAAiF;EACjF,gCAAkF;AToaxF;;AStcA;EAsCI,qBVzF0B;EU0F1B,cV7F0B;ACigB9B;;AS3cA;EA0CI,qBVhF8B;EUiF9B,cVjG0B;ACsgB9B;;AShdA;EA6CM,iDVnF4B;AC0flC;;ASpdA;EAgDI,qBVrG0B;EUsG1B,cVvG0B;AC+gB9B;;ASzdA;EAoDI,6BAA6B;EAC7B,yBAAyB;EACzB,cV3G0B;EU4G1B,0BA1F8B;ATmgBlC;;ASheA;EA4DM,4BV3GwB;EU4GxB,cVnHwB;AC2hB9B;;ASreA;EAgEM,yBChB2B;EDiB3B,cVvHwB;ACgiB9B;;AS1eA;;EAoEM,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;AT2atB;;ASjfA;EAwEI,gBAvG0B;EAwG1B,yBAvGmC;EAwGnC,cVhH8B;EUiH9B,qBAvG0B;ATohB9B;;ASxfA;EA8EM,cVpH4B;EUqH5B,0BAzGmC;ATuhBzC;;AS7fA;EAoFM,uBVjIyB;EUkIzB,yBAAyB;EACzB,cVhJuB;AC6jB7B;;ASngBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,cVrJqB;ACmkB7B;;ASzgBA;EA8FQ,yBAAyB;EACzB,cVzJqB;ACwkB7B;;AS9gBA;EAiGU,mDV9IqB;AC+jB/B;;ASlhBA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,cVhKqB;ACklB7B;;ASxhBA;;EAyGQ,uBVtJuB;EUuJvB,mBVvJuB;EUwJvB,gBAAgB;ATobxB;;AS/hBA;EA6GQ,yBVvKqB;EUwKrB,YV3JuB;ACilB/B;;ASpiBA;EAiHU,uBCjEuB;AVwfjC;;ASxiBA;;EAoHU,yBV9KmB;EU+KnB,yBAAyB;EACzB,gBAAgB;EAChB,YVpKqB;AC6lB/B;;AShjBA;EA0HU,gEAA4E;AT0btF;;ASpjBA;EA4HQ,6BAA6B;EAC7B,mBV1KuB;EU2KvB,YV3KuB;ACumB/B;;AS1jBA;EAmIU,uBVhLqB;EUiLrB,mBVjLqB;EUkLrB,cV/LmB;AC0nB7B;;AShkBA;EAwIY,4DAA8D;AT4b1E;;ASpkBA;EA8Ic,gEAA4E;AT0b1F;;ASxkBA;;EAiJU,6BAA6B;EAC7B,mBV/LqB;EUgMrB,gBAAgB;EAChB,YVjMqB;AC6nB/B;;AShlBA;EAsJQ,6BAA6B;EAC7B,qBVjNqB;EUkNrB,cVlNqB;ACgpB7B;;AStlBA;EA6JU,yBVvNmB;EUwNnB,YV3MqB;ACwoB/B;;AS3lBA;EAqKc,4DAA8D;AT0b5E;;AS/lBA;;EAwKU,6BAA6B;EAC7B,qBVnOmB;EUoOnB,gBAAgB;EAChB,cVrOmB;ACiqB7B;;ASvmBA;EAoFM,yBV9IuB;EU+IvB,yBAAyB;EACzB,YVnIyB;AC0pB/B;;AS7mBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,YVxIuB;ACgqB/B;;ASnnBA;EA8FQ,yBAAyB;EACzB,YV5IuB;ACqqB/B;;ASxnBA;EAiGU,gDV3JmB;ACsrB7B;;AS5nBA;EAoGQ,uBCpDyB;EDqDzB,yBAAyB;EACzB,YVnJuB;AC+qB/B;;ASloBA;;EAyGQ,yBVnKqB;EUoKrB,qBVpKqB;EUqKrB,gBAAgB;AT8hBxB;;ASzoBA;EA6GQ,uBV1JuB;EU2JvB,cVxKqB;ACwsB7B;;AS9oBA;EAiHU,yBCjEuB;AVkmBjC;;ASlpBA;;EAoHU,uBVjKqB;EUkKrB,yBAAyB;EACzB,gBAAgB;EAChB,cVjLmB;ACotB7B;;AS1pBA;EA0HU,4DAA4E;AToiBtF;;AS9pBA;EA4HQ,6BAA6B;EAC7B,qBVvLqB;EUwLrB,cVxLqB;AC8tB7B;;ASpqBA;EAmIU,yBV7LmB;EU8LnB,qBV9LmB;EU+LnB,YVlLqB;ACutB/B;;AS1qBA;EAwIY,gEAA8D;ATsiB1E;;AS9qBA;EA8Ic,4DAA4E;AToiB1F;;ASlrBA;;EAiJU,6BAA6B;EAC7B,qBV5MmB;EU6MnB,gBAAgB;EAChB,cV9MmB;ACovB7B;;AS1rBA;EAsJQ,6BAA6B;EAC7B,mBVpMuB;EUqMvB,YVrMuB;AC6uB/B;;AShsBA;EA6JU,uBV1MqB;EU2MrB,cVxNmB;AC+vB7B;;ASrsBA;EAqKc,gEAA8D;AToiB5E;;ASzsBA;;EAwKU,6BAA6B;EAC7B,mBVtNqB;EUuNrB,gBAAgB;EAChB,YVxNqB;AC8vB/B;;ASjtBA;EAoFM,4BVnIwB;EUoIxB,yBAAyB;EACzB,yBClEe;AVmsBrB;;ASvtBA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,yBCvEa;AVysBrB;;AS7tBA;EA8FQ,yBAAyB;EACzB,yBC3Ea;AV8sBrB;;ASluBA;EAiGU,mDVhJoB;ACqxB9B;;AStuBA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,yBClFa;AVwtBrB;;AS5uBA;;EAyGQ,4BVxJsB;EUyJtB,wBVzJsB;EU0JtB,gBAAgB;ATwoBxB;;ASnvBA;EA6GQ,oCCzFa;ED0Fb,iBV7JsB;ACuyB9B;;ASxvBA;EAiHU,oCCjEuB;AV4sBjC;;AS5vBA;;EAoHU,oCChGW;EDiGX,yBAAyB;EACzB,gBAAgB;EAChB,iBVtKoB;ACmzB9B;;ASpwBA;EA0HU,sFAA4E;AT8oBtF;;ASxwBA;EA4HQ,6BAA6B;EAC7B,wBV5KsB;EU6KtB,iBV7KsB;AC6zB9B;;AS9wBA;EAmIU,4BVlLoB;EUmLpB,wBVnLoB;EUoLpB,yBCjHW;AVgwBrB;;ASpxBA;EAwIY,sEAA8D;ATgpB1E;;ASxxBA;EA8Ic,sFAA4E;AT8oB1F;;AS5xBA;;EAiJU,6BAA6B;EAC7B,wBVjMoB;EUkMpB,gBAAgB;EAChB,iBVnMoB;ACm1B9B;;ASpyBA;EAsJQ,6BAA6B;EAC7B,gCCnIa;EDoIb,yBCpIa;AVsxBrB;;AS1yBA;EA6JU,oCCzIW;ED0IX,iBV7MoB;AC81B9B;;AS/yBA;EAqKc,sEAA8D;AT8oB5E;;ASnzBA;;EAwKU,6BAA6B;EAC7B,gCCrJW;EDsJX,gBAAgB;EAChB,yBCvJW;AVuyBrB;;AS3zBA;EAoFM,yBV1IwB;EU2IxB,yBAAyB;EACzB,WChEU;AV2yBhB;;ASj0BA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVizBhB;;ASv0BA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVszBhB;;AS50BA;EAiGU,gDVvJoB;ACs4B9B;;ASh1BA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVg0BhB;;ASt1BA;;EAyGQ,yBV/JsB;EUgKtB,qBVhKsB;EUiKtB,gBAAgB;ATkvBxB;;AS71BA;EA6GQ,sBCvFQ;EDwFR,cVpKsB;ACw5B9B;;ASl2BA;EAiHU,yBCjEuB;AVszBjC;;ASt2BA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7KoB;ACo6B9B;;AS92BA;EA0HU,0DAA4E;ATwvBtF;;ASl3BA;EA4HQ,6BAA6B;EAC7B,qBVnLsB;EUoLtB,cVpLsB;AC86B9B;;ASx3BA;EAmIU,yBVzLoB;EU0LpB,qBV1LoB;EU2LpB,WC/GM;AVw2BhB;;AS93BA;EAwIY,gEAA8D;AT0vB1E;;ASl4BA;EA8Ic,0DAA4E;ATwvB1F;;ASt4BA;;EAiJU,6BAA6B;EAC7B,qBVxMoB;EUyMpB,gBAAgB;EAChB,cV1MoB;ACo8B9B;;AS94BA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV83BhB;;ASp5BA;EA6JU,sBCvIM;EDwIN,cVpNoB;AC+8B9B;;ASz5BA;EAqKc,gEAA8D;ATwvB5E;;AS75BA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV+4BhB;;ASr6BA;EAoFM,yBV5H4B;EU6H5B,yBAAyB;EACzB,WChEU;AVq5BhB;;AS36BA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AV25BhB;;ASj7BA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVg6BhB;;ASt7BA;EAiGU,iDVzIwB;ACk+BlC;;AS17BA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AV06BhB;;ASh8BA;;EAyGQ,yBVjJ0B;EUkJ1B,qBVlJ0B;EUmJ1B,gBAAgB;AT41BxB;;ASv8BA;EA6GQ,sBCvFQ;EDwFR,cVtJ0B;ACo/BlC;;AS58BA;EAiHU,yBCjEuB;AVg6BjC;;ASh9BA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV/JwB;ACggClC;;ASx9BA;EA0HU,0DAA4E;ATk2BtF;;AS59BA;EA4HQ,6BAA6B;EAC7B,qBVrK0B;EUsK1B,cVtK0B;AC0gClC;;ASl+BA;EAmIU,yBV3KwB;EU4KxB,qBV5KwB;EU6KxB,WC/GM;AVk9BhB;;ASx+BA;EAwIY,gEAA8D;ATo2B1E;;AS5+BA;EA8Ic,0DAA4E;ATk2B1F;;ASh/BA;;EAiJU,6BAA6B;EAC7B,qBV1LwB;EU2LxB,gBAAgB;EAChB,cV5LwB;ACgiClC;;ASx/BA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVw+BhB;;AS9/BA;EA6JU,sBCvIM;EDwIN,cVtMwB;AC2iClC;;ASngCA;EAqKc,gEAA8D;ATk2B5E;;ASvgCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVy/BhB;;AS/gCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV++BrE;;ASphCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVq/BrE;;AS1hCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AV2/BrE;;AShiCA;EAoFM,yBV1H4B;EU2H5B,yBAAyB;EACzB,WChEU;AVghChB;;AStiCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVshChB;;AS5iCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AV2hChB;;ASjjCA;EAiGU,iDVvIwB;AC2lClC;;ASrjCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVqiChB;;AS3jCA;;EAyGQ,yBV/I0B;EUgJ1B,qBVhJ0B;EUiJ1B,gBAAgB;ATu9BxB;;ASlkCA;EA6GQ,sBCvFQ;EDwFR,cVpJ0B;AC6mClC;;ASvkCA;EAiHU,yBCjEuB;AV2hCjC;;AS3kCA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV7JwB;ACynClC;;ASnlCA;EA0HU,0DAA4E;AT69BtF;;ASvlCA;EA4HQ,6BAA6B;EAC7B,qBVnK0B;EUoK1B,cVpK0B;ACmoClC;;AS7lCA;EAmIU,yBVzKwB;EU0KxB,qBV1KwB;EU2KxB,WC/GM;AV6kChB;;ASnmCA;EAwIY,gEAA8D;AT+9B1E;;ASvmCA;EA8Ic,0DAA4E;AT69B1F;;AS3mCA;;EAiJU,6BAA6B;EAC7B,qBVxLwB;EUyLxB,gBAAgB;EAChB,cV1LwB;ACypClC;;ASnnCA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVmmChB;;ASznCA;EA6JU,sBCvIM;EDwIN,cVpMwB;ACoqClC;;AS9nCA;EAqKc,gEAA8D;AT69B5E;;ASloCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVonChB;;AS1oCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV0mCrE;;AS/oCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVgnCrE;;ASrpCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVsnCrE;;AS3pCA;EAoFM,yBV3H4B;EU4H5B,yBAAyB;EACzB,WChEU;AV2oChB;;ASjqCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVipChB;;ASvqCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVspChB;;AS5qCA;EAiGU,kDVxIwB;ACutClC;;AShrCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVgqChB;;AStrCA;;EAyGQ,yBVhJ0B;EUiJ1B,qBVjJ0B;EUkJ1B,gBAAgB;ATklCxB;;AS7rCA;EA6GQ,sBCvFQ;EDwFR,cVrJ0B;ACyuClC;;ASlsCA;EAiHU,yBCjEuB;AVspCjC;;AStsCA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV9JwB;ACqvClC;;AS9sCA;EA0HU,0DAA4E;ATwlCtF;;ASltCA;EA4HQ,6BAA6B;EAC7B,qBVpK0B;EUqK1B,cVrK0B;AC+vClC;;ASxtCA;EAmIU,yBV1KwB;EU2KxB,qBV3KwB;EU4KxB,WC/GM;AVwsChB;;AS9tCA;EAwIY,gEAA8D;AT0lC1E;;ASluCA;EA8Ic,0DAA4E;ATwlC1F;;AStuCA;;EAiJU,6BAA6B;EAC7B,qBVzLwB;EU0LxB,gBAAgB;EAChB,cV3LwB;ACqxClC;;AS9uCA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV8tChB;;ASpvCA;EA6JU,sBCvIM;EDwIN,cVrMwB;ACgyClC;;ASzvCA;EAqKc,gEAA8D;ATwlC5E;;AS7vCA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV+uChB;;ASrwCA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVquCrE;;AS1wCA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AV2uCrE;;AShxCA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVivCrE;;AStxCA;EAoFM,yBV7H4B;EU8H5B,yBAAyB;EACzB,WChEU;AVswChB;;AS5xCA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AV4wChB;;ASlyCA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVixChB;;ASvyCA;EAiGU,kDV1IwB;ACo1ClC;;AS3yCA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AV2xChB;;ASjzCA;;EAyGQ,yBVlJ0B;EUmJ1B,qBVnJ0B;EUoJ1B,gBAAgB;AT6sCxB;;ASxzCA;EA6GQ,sBCvFQ;EDwFR,cVvJ0B;ACs2ClC;;AS7zCA;EAiHU,yBCjEuB;AVixCjC;;ASj0CA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cVhKwB;ACk3ClC;;ASz0CA;EA0HU,0DAA4E;ATmtCtF;;AS70CA;EA4HQ,6BAA6B;EAC7B,qBVtK0B;EUuK1B,cVvK0B;AC43ClC;;ASn1CA;EAmIU,yBV5KwB;EU6KxB,qBV7KwB;EU8KxB,WC/GM;AVm0ChB;;ASz1CA;EAwIY,gEAA8D;ATqtC1E;;AS71CA;EA8Ic,0DAA4E;ATmtC1F;;ASj2CA;;EAiJU,6BAA6B;EAC7B,qBV3LwB;EU4LxB,gBAAgB;EAChB,cV7LwB;ACk5ClC;;ASz2CA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AVy1ChB;;AS/2CA;EA6JU,sBCvIM;EDwIN,cVvMwB;AC65ClC;;ASp3CA;EAqKc,gEAA8D;ATmtC5E;;ASx3CA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AV02ChB;;ASh4CA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVg2CrE;;ASr4CA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVs2CrE;;AS34CA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AV42CrE;;ASj5CA;EAoFM,yBV9H4B;EU+H5B,yBAAyB;EACzB,yBClEe;AVm4CrB;;ASv5CA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,yBCvEa;AVy4CrB;;AS75CA;EA8FQ,yBAAyB;EACzB,yBC3Ea;AV84CrB;;ASl6CA;EAiGU,mDV3IwB;ACg9ClC;;ASt6CA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,yBClFa;AVw5CrB;;AS56CA;;EAyGQ,yBVnJ0B;EUoJ1B,qBVpJ0B;EUqJ1B,gBAAgB;ATw0CxB;;ASn7CA;EA6GQ,oCCzFa;ED0Fb,cVxJ0B;ACk+ClC;;ASx7CA;EAiHU,oCCjEuB;AV44CjC;;AS57CA;;EAoHU,oCChGW;EDiGX,yBAAyB;EACzB,gBAAgB;EAChB,cVjKwB;AC8+ClC;;ASp8CA;EA0HU,sFAA4E;AT80CtF;;ASx8CA;EA4HQ,6BAA6B;EAC7B,qBVvK0B;EUwK1B,cVxK0B;ACw/ClC;;AS98CA;EAmIU,yBV7KwB;EU8KxB,qBV9KwB;EU+KxB,yBCjHW;AVg8CrB;;ASp9CA;EAwIY,gEAA8D;ATg1C1E;;ASx9CA;EA8Ic,sFAA4E;AT80C1F;;AS59CA;;EAiJU,6BAA6B;EAC7B,qBV5LwB;EU6LxB,gBAAgB;EAChB,cV9LwB;AC8gDlC;;ASp+CA;EAsJQ,6BAA6B;EAC7B,gCCnIa;EDoIb,yBCpIa;AVs9CrB;;AS1+CA;EA6JU,oCCzIW;ED0IX,cVxMwB;ACyhDlC;;AS/+CA;EAqKc,gEAA8D;AT80C5E;;ASn/CA;;EAwKU,6BAA6B;EAC7B,gCCrJW;EDsJX,gBAAgB;EAChB,yBCvJW;AVu+CrB;;AS3/CA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AV29CrE;;AShgDA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AVi+CrE;;AStgDA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVu+CrE;;AS5gDA;EAoFM,yBVxH2B;EUyH3B,yBAAyB;EACzB,WChEU;AV4/ChB;;ASlhDA;EAyFQ,yBCzCyB;ED0CzB,yBAAyB;EACzB,WCrEQ;AVkgDhB;;ASxhDA;EA8FQ,yBAAyB;EACzB,WCzEQ;AVugDhB;;AS7hDA;EAiGU,kDVrIuB;ACqkDjC;;ASjiDA;EAoGQ,yBCpDyB;EDqDzB,yBAAyB;EACzB,WChFQ;AVihDhB;;ASviDA;;EAyGQ,yBV7IyB;EU8IzB,qBV9IyB;EU+IzB,gBAAgB;ATm8CxB;;AS9iDA;EA6GQ,sBCvFQ;EDwFR,cVlJyB;ACulDjC;;ASnjDA;EAiHU,yBCjEuB;AVugDjC;;ASvjDA;;EAoHU,sBC9FM;ED+FN,yBAAyB;EACzB,gBAAgB;EAChB,cV3JuB;ACmmDjC;;AS/jDA;EA0HU,0DAA4E;ATy8CtF;;ASnkDA;EA4HQ,6BAA6B;EAC7B,qBVjKyB;EUkKzB,cVlKyB;AC6mDjC;;ASzkDA;EAmIU,yBVvKuB;EUwKvB,qBVxKuB;EUyKvB,WC/GM;AVyjDhB;;AS/kDA;EAwIY,gEAA8D;AT28C1E;;ASnlDA;EA8Ic,0DAA4E;ATy8C1F;;ASvlDA;;EAiJU,6BAA6B;EAC7B,qBVtLuB;EUuLvB,gBAAgB;EAChB,cVxLuB;ACmoDjC;;AS/lDA;EAsJQ,6BAA6B;EAC7B,kBCjIQ;EDkIR,WClIQ;AV+kDhB;;ASrmDA;EA6JU,sBCvIM;EDwIN,cVlMuB;AC8oDjC;;AS1mDA;EAqKc,gEAA8D;ATy8C5E;;AS9mDA;;EAwKU,6BAA6B;EAC7B,kBCnJM;EDoJN,gBAAgB;EAChB,WCrJM;AVgmDhB;;AStnDA;EAiLU,yBCpJsC;EDqJtC,cC7I2D;AVslDrE;;AS3nDA;EAqLY,yBCrIqB;EDsIrB,yBAAyB;EACzB,cClJyD;AV4lDrE;;ASjoDA;EA0LY,yBC1IqB;ED2IrB,yBAAyB;EACzB,cCvJyD;AVkmDrE;;ASvoDA;EARE,kBVdc;ACiqDhB;;ASrpDE;EACE,kBVkBc;ACsoDlB;;AS/oDA;EANE,eVjBW;AC0qDb;;ASnpDA;EAJE,kBVpBc;AC+qDhB;;ASvpDA;EAFE,iBVvBa;ACorDf;;AS3pDA;;EAyMI,uBVtP2B;EUuP3B,qBV5P0B;EU6P1B,gBAjOyB;EAkOzB,YAjOyB;ATwrD7B;;ASnqDA;EA8MI,aAAa;EACb,WAAW;ATy9Cf;;ASxqDA;EAiNI,6BAA6B;EAC7B,oBAAoB;AT29CxB;;AS7qDA;ERnDE,kBAAkB;EAKhB,6BAAmC;EACnC,4BAAkC;EQmQhC,6BAA6B;AT89CnC;;ASprDA;EAwNI,4BVvQ0B;EUwQ1B,qBV3Q0B;EU4Q1B,cV9Q0B;EU+Q1B,gBAAgB;EAChB,oBAAoB;ATg+CxB;;AS5rDA;EA8NI,qBVlNmB;EUmNnB,gCAA0D;EAC1D,iCAA2D;ATk+C/D;;ASh+CA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;ATm+C7B;;ASv+CA;EAMI,qBAAqB;ATq+CzB;;AS3+CA;ER1GI,oBQkHwC;ATu+C5C;;AS/+CA;EAUI,sBAAsB;ATy+C1B;;ASn/CA;EAYI,mBAAmB;AT2+CvB;;ASv/CA;EA1OE,kBVdc;ACmvDhB;;ASvuDE;EACE,kBVkBc;ACwtDlB;;AS//CA;EAtOE,kBVpBc;AC6vDhB;;ASngDA;EApOE,iBVvBa;ACkwDf;;ASvgDA;EA0BQ,4BAA4B;EAC5B,yBAAyB;ATi/CjC;;AS5gDA;EA6BQ,6BAA6B;EAC7B,0BAA0B;ERxI9B,kBQyIwC;ATm/C5C;;ASlhDA;ER1GI,eQ2IqC;ATq/CzC;;ASthDA;EAoCQ,UAAU;ATs/ClB;;AS1hDA;EA0CQ,UAAU;ATo/ClB;;AS9hDA;EA4CU,UAAU;ATs/CpB;;ASliDA;EA8CQ,YAAY;EACZ,cAAc;ATw/CtB;;ASviDA;EAiDI,uBAAuB;AT0/C3B;;AS3iDA;EAoDQ,oBAAoB;EACpB,qBAAqB;AT2/C7B;;AShjDA;EAuDI,yBAAyB;AT6/C7B;;ASpjDA;EA0DQ,oBAAoB;EACpB,qBAAqB;AT8/C7B;;ACzvDE;EQiQM;IACE,oBAlTyD;ET8yDjE;ES1/CM;;IAEE,qBAtT0F;ETkzDlG;ESjgDM;IACE,kBV1TM;EC6zDd;ESpgDM;IACE,eV3TG;ECi0DX;AACF;;ACrwDE;EQ6PM;IACE,qBAlTyL;ET8zDjM;ES1gDM;;IAEE,kBV9TM;EC00Dd;ESjhDM;IACE,eV3TG;EC80DX;ESphDM;IACE,kBV5TM;ECk1Dd;AACF;;AWl3DA;EACE,YAAY;EACZ,cAAc;EACd,kBAAkB;EAClB,WAAW;AXq3Db;;AWz3DA;EAMI,0BAA0B;EAC1B,kBZyCM;EYxCN,mBZwCM;EYvCN,WAAW;AXu3Df;;AC/wDE;EUjHF;IAWI,gBAAuC;EX03DzC;AACF;;AC3wDI;EU3HJ;IAcM,iBAAqE;EX63DzE;AACF;;AClwDI;EU1IJ;IAiBM,iBAAiE;EXg4DrE;AACF;;AClxDI;EUhIJ;IAoBM,iBAAqE;EXm4DzE;AACF;;ACzwDI;EU/IJ;IAuBM,iBAAiE;EXs4DrE;AACF;;AY34DA;EAII,kBAAkB;AZ24DtB;;AY/4DA;;;;;;;EAcM,kBAhC2B;AZ26DjC;;AYz5DA;;;;;;EAqBI,cbvC0B;EawC1B,gBbHiB;EaIjB,kBA3C+B;AZw7DnC;;AYp6DA;EAyBI,cAAc;EACd,oBAAoB;AZ+4DxB;;AYz6DA;EA4BM,eAAe;AZi5DrB;;AY76DA;EA8BI,iBAAiB;EACjB,uBAAuB;AZm5D3B;;AYl7DA;EAiCM,oBAAoB;AZq5D1B;;AYt7DA;EAmCI,gBAAgB;EAChB,uBAAuB;AZu5D3B;;AY37DA;EAsCM,oBAAoB;AZy5D1B;;AY/7DA;EAwCI,iBAAiB;EACjB,oBAAoB;AZ25DxB;;AYp8DA;EA2CI,kBAAkB;EAClB,uBAAuB;AZ65D3B;;AYz8DA;EA8CI,cAAc;EACd,kBAAkB;AZ+5DtB;;AY98DA;EAiDI,4Bb5D0B;EEuK1B,8BF1K0B;EaiE1B,qBAjEqC;AZk+DzC;;AYp9DA;EAqDI,4BAA4B;EXuG5B,gBWtGmC;EACnC,eAAe;AZm6DnB;;AY19DA;EAyDM,wBAAwB;AZq6D9B;;AY99DA;EA2DQ,4BAA4B;AZu6DpC;;AYl+DA;EA6DQ,4BAA4B;AZy6DpC;;AYt+DA;EA+DQ,4BAA4B;AZ26DpC;;AY1+DA;EAiEQ,4BAA4B;AZ66DpC;;AY9+DA;EAmEI,wBAAwB;EXyFxB,gBWxFmC;EACnC,eAAe;AZ+6DnB;;AYp/DA;EAuEM,uBAAuB;EACvB,iBAAiB;AZi7DvB;;AYz/DA;EA0EQ,uBAAuB;AZm7D/B;;AY7/DA;EX4JI,gBWhFmC;AZq7DvC;;AYjgEA;EA8EI,gBAAgB;EAChB,iBAAiB;EACjB,kBAAkB;AZu7DtB;;AYvgEA;EAkFM,eAAe;AZy7DrB;;AY3gEA;EAoFM,kBAAkB;AZ27DxB;;AY/gEA;EAsFM,qBAAqB;AZ67D3B;;AYnhEA;EAwFM,kBAAkB;AZ+7DxB;;AYvhEA;EX2CE,iCAAiC;EWgD/B,gBAAgB;EAChB,qBAxG8B;EAyG9B,gBAAgB;EAChB,iBAAiB;AZi8DrB;;AY/hEA;;EAiGI,cAAc;AZm8DlB;;AYpiEA;EAmGI,WAAW;AZq8Df;;AYxiEA;;EAsGM,yBbpHwB;EaqHxB,qBAhHmC;EAiHnC,qBAhHmC;EAiHnC,mBAAmB;AZu8DzB;;AYhjEA;EA2GM,cb7HwB;ACskE9B;;AYpjEA;EA6GQ,mBAAmB;AZ28D3B;;AYxjEA;;EAiHQ,qBAvHsC;EAwHtC,cbpIsB;ACglE9B;;AY9jEA;;EAsHQ,qBAzHsC;EA0HtC,cbzIsB;ACslE9B;;AYpkEA;;EA6HY,sBAjI4C;AZ6kExD;;AYzkEA;EAgIM,aAAa;AZ68DnB;;AY7kEA;EAmII,kBbrHY;ACmkEhB;;AYjlEA;EAqII,ebxHS;ACwkEb;;AYrlEA;EAuII,kBb3HY;AC6kEhB;;AYzlEA;EAyII,iBb9HW;ACklEf;;Aa/mEA;EACE,mBAAmB;EACnB,oBAAoB;EACpB,uBAAuB;EACvB,cAVsB;EAWtB,aAXsB;Ab6nExB;;AavnEA;EAQI,YAbwB;EAcxB,WAdwB;AbioE5B;;Aa5nEA;EAWI,YAfyB;EAgBzB,WAhByB;AbqoE7B;;AajoEA;EAcI,YAjBwB;EAkBxB,WAlBwB;AbyoE5B;;AarnEA;EACE,uBAAuB;EACvB,cAAc;EACd,oBAAoB;EACpB,eAAe;EACf,mBA5BsB;EA6BtB,mBAAmB;AbwnErB;;Aa9nEA;EAQI,YAAY;EACZ,cAAc;Ab0nElB;;AanoEA;EAYQ,oBA/BkB;Ab0pE1B;;AavoEA;EAiBQ,mBApCkB;Ab8pE1B;;AatnEA;EACE,aAAa;AbynEf;;AclqEA;EACE,cAAc;EACd,kBAAkB;AdqqEpB;;AcvqEA;EAII,cAAc;EACd,YAAY;EACZ,WAAW;AduqEf;;Ac7qEA;EAQM,qBf4DiB;AC6mEvB;;AcjrEA;EAUI,WAAW;Ad2qEf;;AcrrEA;;;;;;;;;;;;;;;;;EA+BM,YAAY;EACZ,WAAW;Ad0qEjB;;Ac1sEA;EAmCI,iBAAiB;Ad2qErB;;Ac9sEA;EAqCI,gBAAgB;Ad6qEpB;;AcltEA;EAuCI,gBAAgB;Ad+qEpB;;ActtEA;EAyCI,qBAAqB;AdirEzB;;Ac1tEA;EA2CI,gBAAgB;AdmrEpB;;Ac9tEA;EA6CI,mBAAmB;AdqrEvB;;AcluEA;EA+CI,gBAAgB;AdurEpB;;ActuEA;EAiDI,qBAAqB;AdyrEzB;;Ac1uEA;EAmDI,iBAAiB;Ad2rErB;;Ac9uEA;EAqDI,sBAAsB;Ad6rE1B;;AclvEA;EAuDI,iBAAiB;Ad+rErB;;ActvEA;EAyDI,sBAAsB;AdisE1B;;Ac1vEA;EA2DI,sBAAsB;AdmsE1B;;Ac9vEA;EA6DI,iBAAiB;AdqsErB;;AclwEA;EA+DI,iBAAiB;AdusErB;;ActwEA;EAmEM,YAAwB;EACxB,WAAuB;AdusE7B;;Ac3wEA;EAmEM,YAAwB;EACxB,WAAuB;Ad4sE7B;;AchxEA;EAmEM,YAAwB;EACxB,WAAuB;AditE7B;;AcrxEA;EAmEM,YAAwB;EACxB,WAAuB;AdstE7B;;Ac1xEA;EAmEM,YAAwB;EACxB,WAAuB;Ad2tE7B;;Ac/xEA;EAmEM,YAAwB;EACxB,WAAuB;AdguE7B;;AcpyEA;EAmEM,aAAwB;EACxB,YAAuB;AdquE7B;;AelyEA;EAEE,4BhBA4B;EgBC5B,kBhBwDU;EgBvDV,kBAAkB;EAEhB,sCAXoD;Af8yExD;;AezyEA;EAUI,mBAAmB;EACnB,0BAA0B;AfmyE9B;;Ae9yEA;EAaI,mBAAmB;AfqyEvB;;AelzEA;;EAgBI,iBhBZ2B;ACmzE/B;;AevzEA;EAkBI,uBAAuB;AfyyE3B;;Ae3zEA;EdiLI,ac7J4B;EAC5B,kBAAkB;EAClB,WAAW;Af2yEf;;Aej0EA;;;EA0BI,mBAAmB;Af6yEvB;;Aev0EA;EAgCM,uBhB5ByB;EgB6BzB,chB1CuB;ACq1E7B;;Ae50EA;EAgCM,yBhBzCuB;EgB0CvB,YhB7ByB;AC60E/B;;Aej1EA;EAgCM,4BhB9BwB;EgB+BxB,yBLoCe;AVixErB;;Aet1EA;EAgCM,yBhBrCwB;EgBsCxB,WLsCU;AVoxEhB;;Ae31EA;EAgCM,yBhBvB4B;EgBwB5B,WLsCU;AVyxEhB;;Aeh2EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AV+wErE;;Aer2EA;EAgCM,yBhBrB4B;EgBsB5B,WLsCU;AVmyEhB;;Ae12EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVyxErE;;Ae/2EA;EAgCM,yBhBtB4B;EgBuB5B,WLsCU;AV6yEhB;;Aep3EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVmyErE;;Aez3EA;EAgCM,yBhBxB4B;EgByB5B,WLsCU;AVuzEhB;;Ae93EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AV6yErE;;Aen4EA;EAgCM,yBhBzB4B;EgB0B5B,yBLoCe;AVm0ErB;;Aex4EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVuzErE;;Ae74EA;EAgCM,yBhBnB2B;EgBoB3B,WLsCU;AV20EhB;;Ael5EA;EAuCU,yBLuCsC;EKtCtC,cL8C2D;AVi0ErE;;AgBx5EA;EAEE,qBAAqB;EACrB,wBAAwB;EACxB,YAAY;EACZ,qBjByDqB;EiBxDrB,cAAc;EACd,YjBoBW;EiBnBX,gBAAgB;EAChB,UAAU;EACV,WAAW;AhB05Eb;;AgBp6EA;EAYI,yBjBX2B;ACu6E/B;;AgBx6EA;EAcI,yBjBjB0B;AC+6E9B;;AgB56EA;EAgBI,yBjBnB0B;ACm7E9B;;AgBh7EA;EAkBI,yBjBrB0B;EiBsB1B,YAAY;AhBk6EhB;;AgBr7EA;EAyBQ,uBjBpBuB;ACo7E/B;;AgBz7EA;EA2BQ,uBjBtBuB;ACw7E/B;;AgB77EA;EA6BQ,uBjBxBuB;AC47E/B;;AgBj8EA;EA+BQ,mEAA2F;AhBs6EnG;;AgBr8EA;EAyBQ,yBjBjCqB;ACi9E7B;;AgBz8EA;EA2BQ,yBjBnCqB;ACq9E7B;;AgB78EA;EA6BQ,yBjBrCqB;ACy9E7B;;AgBj9EA;EA+BQ,qEAA2F;AhBs7EnG;;AgBr9EA;EAyBQ,4BjBtBsB;ACs9E9B;;AgBz9EA;EA2BQ,4BjBxBsB;AC09E9B;;AgB79EA;EA6BQ,4BjB1BsB;AC89E9B;;AgBj+EA;EA+BQ,wEAA2F;AhBs8EnG;;AgBr+EA;EAyBQ,yBjB7BsB;AC6+E9B;;AgBz+EA;EA2BQ,yBjB/BsB;ACi/E9B;;AgB7+EA;EA6BQ,yBjBjCsB;ACq/E9B;;AgBj/EA;EA+BQ,qEAA2F;AhBs9EnG;;AgBr/EA;EAyBQ,yBjBf0B;AC++ElC;;AgBz/EA;EA2BQ,yBjBjB0B;ACm/ElC;;AgB7/EA;EA6BQ,yBjBnB0B;ACu/ElC;;AgBjgFA;EA+BQ,qEAA2F;AhBs+EnG;;AgBrgFA;EAyBQ,yBjBb0B;AC6/ElC;;AgBzgFA;EA2BQ,yBjBf0B;ACigFlC;;AgB7gFA;EA6BQ,yBjBjB0B;ACqgFlC;;AgBjhFA;EA+BQ,qEAA2F;AhBs/EnG;;AgBrhFA;EAyBQ,yBjBd0B;AC8gFlC;;AgBzhFA;EA2BQ,yBjBhB0B;ACkhFlC;;AgB7hFA;EA6BQ,yBjBlB0B;ACshFlC;;AgBjiFA;EA+BQ,qEAA2F;AhBsgFnG;;AgBriFA;EAyBQ,yBjBhB0B;ACgiFlC;;AgBziFA;EA2BQ,yBjBlB0B;ACoiFlC;;AgB7iFA;EA6BQ,yBjBpB0B;ACwiFlC;;AgBjjFA;EA+BQ,qEAA2F;AhBshFnG;;AgBrjFA;EAyBQ,yBjBjB0B;ACijFlC;;AgBzjFA;EA2BQ,yBjBnB0B;ACqjFlC;;AgB7jFA;EA6BQ,yBjBrB0B;ACyjFlC;;AgBjkFA;EA+BQ,qEAA2F;AhBsiFnG;;AgBrkFA;EAyBQ,yBjBXyB;AC2jFjC;;AgBzkFA;EA2BQ,yBjBbyB;AC+jFjC;;AgB7kFA;EA6BQ,yBjBfyB;ACmkFjC;;AgBjlFA;EA+BQ,qEAA2F;AhBsjFnG;;AgBrlFA;EAkCI,gCAtCkC;UAsClC,wBAtCkC;EAuClC,2CAAmC;UAAnC,mCAAmC;EACnC,yCAAiC;UAAjC,iCAAiC;EACjC,yCAAiC;UAAjC,iCAAiC;EACjC,yBjBrC2B;EiBsC3B,qEAA0F;EAC1F,6BAA6B;EAC7B,4BAA4B;EAC5B,0BAA0B;AhBujF9B;;AgBjmFA;EA4CM,6BAA6B;AhByjFnC;;AgBrmFA;EA8CM,6BAA6B;AhB2jFnC;;AgBzmFA;EAgDM,oBAAoB;AhB6jF1B;;AgB7mFA;EAoDI,ejBxBY;ACqlFhB;;AgBjnFA;EAsDI,ejB5BY;AC2lFhB;;AgBrnFA;EAwDI,cjB/BW;ACgmFf;;AgB/jFA;EACE;IACE,2BAA2B;EhBkkF7B;EgBjkFA;IACE,4BAA4B;EhBmkF9B;AACF;;AgBxkFA;EACE;IACE,2BAA2B;EhBkkF7B;EgBjkFA;IACE,4BAA4B;EhBmkF9B;AACF;;AiB9mFA;EAEE,uBlBjB6B;EkBkB7B,clB3B4B;AC2oF9B;;AiBnnFA;;EAMI,yBlB1B0B;EkB2B1B,qBA/B6B;EAgC7B,qBA/B6B;EAgC7B,mBAAmB;AjBknFvB;;AiB3nFA;;EAeQ,uBlB9BuB;EkB+BvB,mBlB/BuB;EkBgCvB,clB7CqB;AC8pF7B;;AiBloFA;;EAeQ,yBlB3CqB;EkB4CrB,qBlB5CqB;EkB6CrB,YlBhCuB;ACwpF/B;;AiBzoFA;;EAeQ,4BlBhCsB;EkBiCtB,wBlBjCsB;EkBkCtB,yBPiCa;AV8lFrB;;AiBhpFA;;EAeQ,yBlBvCsB;EkBwCtB,qBlBxCsB;EkByCtB,WPmCQ;AVmmFhB;;AiBvpFA;;EAeQ,yBlBzB0B;EkB0B1B,qBlB1B0B;EkB2B1B,WPmCQ;AV0mFhB;;AiB9pFA;;EAeQ,yBlBvB0B;EkBwB1B,qBlBxB0B;EkByB1B,WPmCQ;AVinFhB;;AiBrqFA;;EAeQ,yBlBxB0B;EkByB1B,qBlBzB0B;EkB0B1B,WPmCQ;AVwnFhB;;AiB5qFA;;EAeQ,yBlB1B0B;EkB2B1B,qBlB3B0B;EkB4B1B,WPmCQ;AV+nFhB;;AiBnrFA;;EAeQ,yBlB3B0B;EkB4B1B,qBlB5B0B;EkB6B1B,yBPiCa;AVwoFrB;;AiB1rFA;;EAeQ,yBlBrByB;EkBsBzB,qBlBtByB;EkBuBzB,WPmCQ;AV6oFhB;;AiBjsFA;;EAoBM,mBAAmB;EACnB,SAAS;AjBkrFf;;AiBvsFA;;EAuBM,yBlBjC4B;EkBkC5B,WP4BU;AVypFhB;;AiB7sFA;;;;EA2BQ,mBAAmB;AjByrF3B;;AiBptFA;;EA6BM,sBAAsB;AjB4rF5B;;AiBztFA;EA+BI,clBvD0B;ACqvF9B;;AiB7tFA;EAiCM,gBAtDsB;AjBsvF5B;;AiBjuFA;EAoCM,yBlB9C4B;EkB+C5B,WPeU;AVkrFhB;;AiBtuFA;;EAwCQ,mBAAmB;AjBmsF3B;;AiB3uFA;;EA2CQ,kBPSQ;EORR,mBAAmB;AjBqsF3B;;AiBjvFA;EA8CI,6BA5DqC;AjBmwFzC;;AiBrvFA;;EAiDM,qBApEgC;EAqEhC,clB1EwB;ACmxF9B;;AiB3vFA;EAoDI,6BAhEqC;AjB2wFzC;;AiB/vFA;;EAuDM,qBAxEgC;EAyEhC,clBhFwB;AC6xF9B;;AiBrwFA;EA0DI,6BAvEqC;AjBsxFzC;;AiBzwFA;;EA+DU,sBAAsB;AjB+sFhC;;AiB9wFA;;EAoEM,iBAAiB;AjB+sFvB;;AiBnxFA;;EAyEU,wBAAwB;AjB+sFlC;;AiBxxFA;EA2EI,WAAW;AjBitFf;;AiB5xFA;EAgFU,yBlBhGoB;ACgzF9B;;AiBhyFA;EAqFY,yBlBrGkB;ACozF9B;;AiBpyFA;EAuFc,4BlBxGgB;ACyzF9B;;AiBxyFA;;EA2FM,qBAAqB;AjBktF3B;;AiB7yFA;EAgGU,yBlBhHoB;ACi0F9B;;AiB/sFA;EhB7DE,iCAAiC;EgBgEjC,cAAc;EACd,kBAAkB;EAClB,eAAe;AjBitFjB;;AkB70FA;EACE,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,2BAA2B;AlBg1F7B;;AkBp1FA;EAMI,qBAAqB;AlBk1FzB;;AkBx1FA;EjB2KI,oBiBnKwC;AlBo1F5C;;AkB51FA;EAUI,sBAAsB;AlBs1F1B;;AkBh2FA;EAYI,mBAAmB;AlBw1FvB;;AkBp2FA;EAgBM,enBYO;AC40Fb;;AkBx2FA;EAmBM,kBnBQU;ACi1FhB;;AkB52FA;EAqBI,uBAAuB;AlB21F3B;;AkBh3FA;EAuBM,qBAAqB;EACrB,oBAAoB;AlB61F1B;;AkBr3FA;EA0BI,yBAAyB;AlB+1F7B;;AkBz3FA;EA6BQ,mBAAmB;AlBg2F3B;;AkB73FA;EA+BQ,eAAe;AlBk2FvB;;AkBj4FA;EjB2KI,eiBzImC;AlBm2FvC;;AkBr4FA;EjB2KI,ciBvIqC;EAE/B,yBAAyB;EACzB,4BAA4B;AlBo2FtC;;AkB34FA;EA6CU,0BAA0B;EAC1B,6BAA6B;AlBk2FvC;;AkB71FA;EACE,mBAAmB;EACnB,4BnBjD4B;EmBkD5B,kBnBOU;EmBNV,cnBzD4B;EmB0D5B,oBAAoB;EACpB,kBnB5Bc;EmB6Bd,WAAW;EACX,uBAAuB;EACvB,gBAAgB;EAChB,oBAAoB;EACpB,qBAAqB;EACrB,mBAAmB;AlBg2FrB;;AkB52FA;EjBwHI,oBiB1GuC;EjB0GvC,uBiBzGyC;AlBk2F7C;;AkBj3FA;EAqBM,uBnBlEyB;EmBmEzB,cnBhFuB;ACg7F7B;;AkBt3FA;EAqBM,yBnB/EuB;EmBgFvB,YnBnEyB;ACw6F/B;;AkB33FA;EAqBM,4BnBpEwB;EmBqExB,yBRFe;AV42FrB;;AkBh4FA;EAqBM,yBnB3EwB;EmB4ExB,WRAU;AV+2FhB;;AkBr4FA;EAqBM,yBnB7D4B;EmB8D5B,WRAU;AVo3FhB;;AkB14FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV02FrE;;AkB/4FA;EAqBM,yBnB3D4B;EmB4D5B,WRAU;AV83FhB;;AkBp5FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVo3FrE;;AkBz5FA;EAqBM,yBnB5D4B;EmB6D5B,WRAU;AVw4FhB;;AkB95FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV83FrE;;AkBn6FA;EAqBM,yBnB9D4B;EmB+D5B,WRAU;AVk5FhB;;AkBx6FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVw4FrE;;AkB76FA;EAqBM,yBnB/D4B;EmBgE5B,yBRFe;AV85FrB;;AkBl7FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AVk5FrE;;AkBv7FA;EAqBM,yBnBzD2B;EmB0D3B,WRAU;AVs6FhB;;AkB57FA;EA4BU,yBRCsC;EQAtC,cRQ2D;AV45FrE;;AkBj8FA;EAgCI,kBnBtDY;AC29FhB;;AkBr8FA;EAkCI,enBzDS;ACg+Fb;;AkBz8FA;EAoCI,kBnB5DY;ACq+FhB;;AkB78FA;EjBwHI,qBiBjF0C;EjBiF1C,sBiBhF0C;AlB06F9C;;AkBl9FA;EjBwHI,qBiB9E0C;EjB8E1C,sBiB7E0C;AlB46F9C;;AkBv9FA;EjBwHI,qBiB3E0C;EjB2E1C,sBiB1E0C;AlB86F9C;;AkB59FA;EjBwHI,gBiB/KmB;EAyGnB,UAAU;EACV,kBAAkB;EAClB,UAAU;AlB+6Fd;;AkBn+FA;EAuDM,8BAA8B;EAC9B,WAAW;EACX,cAAc;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,0DAA0D;EAC1D,+BAA+B;AlBg7FrC;;AkB9+FA;EAgEM,WAAW;EACX,UAAU;AlBk7FhB;;AkBn/FA;EAmEM,WAAW;EACX,UAAU;AlBo7FhB;;AkBx/FA;EAuEM,yBAAmD;AlBq7FzD;;AkB5/FA;EAyEM,yBAAoD;AlBu7F1D;;AkBhgGA;EA2EI,qBnB/DmB;ACw/FvB;;AkBv7FA;EAEI,0BAA0B;AlBy7F9B;;AmB/iGA;;EAGE,sBAAsB;AnBijGxB;;AmBpjGA;;;;EAMI,oBAAoB;AnBqjGxB;;AmB3jGA;;EAQI,iBApBmB;AnB4kGvB;;AmBhkGA;;EAUI,iBArBmB;AnBglGvB;;AmBrkGA;;EAYI,sBAAsB;AnB8jG1B;;AmB5jGA;EACE,cpB9B4B;EoBiC5B,epBLW;EoBMX,gBpBGmB;EoBFnB,kBAnCuB;AnBgmGzB;;AmBnkGA;EAQI,cApCwB;EAqCxB,oBApCyB;AnBmmG7B;;AmBxkGA;EAWI,oBA3B+B;AnB4lGnC;;AmB5kGA;EAgBM,epBnBO;ACmlGb;;AmBhlGA;EAgBM,iBpBlBS;ACslGf;;AmBplGA;EAgBM,epBjBO;ACylGb;;AmBxlGA;EAgBM,iBpBhBS;AC4lGf;;AmB5lGA;EAgBM,kBpBfU;AC+lGhB;;AmBhmGA;EAgBM,epBdO;ACkmGb;;AmBpmGA;EAgBM,kBpBbU;ACqmGhB;;AmBtlGA;EACE,cpB/C4B;EoBkD5B,kBpBrBc;EoBsBd,gBpBjBiB;EoBkBjB,iBA3CyB;AnBkoG3B;;AmB7lGA;EAQI,cpBvD0B;EoBwD1B,gBpBnBiB;AC4mGrB;;AmBlmGA;EAWI,oBA7C+B;AnBwoGnC;;AmBtmGA;EAgBM,epBrCO;AC+nGb;;AmB1mGA;EAgBM,iBpBpCS;ACkoGf;;AmB9mGA;EAgBM,epBnCO;ACqoGb;;AmBlnGA;EAgBM,iBpBlCS;ACwoGf;;AmBtnGA;EAgBM,kBpBjCU;AC2oGhB;;AmB1nGA;EAgBM,epBhCO;AC8oGb;;AmB9nGA;EAgBM,kBpB/BU;ACipGhB;;AoB/qGA;EACE,cAAc;EACd,eAAe;EACf,mBAAmB;EACnB,kBAAkB;EAClB,yBAAyB;ApBkrG3B;;AoB7qGA;EACE,mBAAmB;EACnB,4BrBP4B;EqBQ5B,qBrBmDqB;EqBlDrB,oBAAoB;EACpB,kBrBac;EqBZd,WAAW;EACX,uBAAuB;EACvB,oBAAoB;EACpB,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;EAClB,mBAAmB;ApBgrGrB;;AqB9sGA,eAAA;AC0DA;EAxBE,uBvBnB6B;EuBoB7B,qBvBzB4B;EuB0B5B,kBvBkCU;EuBjCV,cvB/B4B;ACgtG9B;;AC9oGI;EqBjCA,4BvBjC0B;ACotG9B;;AClpGI;EqBjCA,4BvBjC0B;ACwtG9B;;ACtpGI;EqBjCA,4BvBjC0B;AC4tG9B;;AC1pGI;EqBjCA,4BvBjC0B;ACguG9B;;AsB9rGE;EAEE,qBvBjC0B;ACiuG9B;;AsB/rGE;EAIE,qBvBzB8B;EuB0B9B,iDvB1B8B;ACytGlC;;AsB9rGE;;;;;EAEE,4BvBtC0B;EuBuC1B,wBvBvC0B;EuBwC1B,gBAAgB;EAChB,cvB9C0B;ACkvG9B;;AClrGI;;;;;EqBhBE,+BvBhDwB;AC0vG9B;;AC1rGI;;;;;EqBhBE,+BvBhDwB;ACkwG9B;;AClsGI;;;;;EqBhBE,+BvBhDwB;AC0wG9B;;AC1sGI;;;;;EqBhBE,+BvBhDwB;ACkxG9B;;AuBpxGA;EAEE,2DxBN2B;EwBO3B,eAAe;EACf,WAAW;AvBsxGb;;AuBrxGE;EACE,gBAAgB;AvBwxGpB;;AuBpxGI;EACE,mBxBFyB;ACyxG/B;;AuBxxGK;EAMG,mDxBPuB;AC6xG/B;;AuB5xGI;EACE,qBxBfuB;AC8yG7B;;AuBhyGK;EAMG,gDxBpBqB;ACkzG7B;;AuBpyGI;EACE,wBxBJwB;AC2yG9B;;AuBxyGK;EAMG,mDxBTsB;AC+yG9B;;AuB5yGI;EACE,qBxBXwB;AC0zG9B;;AuBhzGK;EAMG,gDxBhBsB;AC8zG9B;;AuBpzGI;EACE,qBxBG4B;ACozGlC;;AuBxzGK;EAMG,iDxBF0B;ACwzGlC;;AuB5zGI;EACE,qBxBK4B;AC0zGlC;;AuBh0GK;EAMG,iDxBA0B;AC8zGlC;;AuBp0GI;EACE,qBxBI4B;ACm0GlC;;AuBx0GK;EAMG,kDxBD0B;ACu0GlC;;AuB50GI;EACE,qBxBE4B;AC60GlC;;AuBh1GK;EAMG,kDxBH0B;ACi1GlC;;AuBp1GI;EACE,qBxBC4B;ACs1GlC;;AuBx1GK;EAMG,mDxBJ0B;AC01GlC;;AuB51GI;EACE,qBxBO2B;ACw1GjC;;AuBh2GK;EAMG,kDxBEyB;AC41GjC;;AuB51GE;EzBmBA,kBC0BgB;EDzBhB,kBCNc;ACm1GhB;;AuB/1GE;EzBoBA,kBCVc;ACy1GhB;;AuBj2GE;EzBoBA,iBCba;AC81Gf;;AuBl2GE;EACE,cAAc;EACd,WAAW;AvBq2Gf;;AuBp2GE;EACE,eAAe;EACf,WAAW;AvBu2Gf;;AuBr2GA;EAGI,qBxB+BmB;EwB9BnB,gDAA4D;EAC5D,iDAA6D;AvBs2GjE;;AuB32GA;EAOI,6BAA6B;EAC7B,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;EACf,gBAAgB;AvBw2GpB;;AuBt2GA;EAEE,cAAc;EACd,eAAe;EACf,eAAe;EACf,2BzB7CkE;EyB8ClE,gBAAgB;AvBw2GlB;;AuB92GA;EAQI,gBA1DsB;EA2DtB,eA1DqB;AvBo6GzB;;AuBn3GA;EAWI,eAAe;AvB42GnB;;AuBv3GA;EAcI,YAAY;AvB62GhB;;AwB96GA;EACE,eAAe;EACf,qBAAqB;EACrB,iBAAiB;EACjB,kBAAkB;AxBi7GpB;;AwBh7GE;EACE,eAAe;AxBm7GnB;;AwBl7GE;EACE,czBF0B;ACu7G9B;;AwBp7GE;;;;;EAGE,czBJ0B;EyBK1B,mBAAmB;AxBy7GvB;;AwBp7GA;EvBkKI,kBuB/JqC;AxBq7GzC;;AyBx8GA;EACE,qBAAqB;EACrB,eAAe;EACf,kBAAkB;EAClB,mBAAmB;AzB28GrB;;AyB/8GA;EAMI,a3BDkB;AE88GtB;;AyBn9GA;EAUM,qB1BU4B;EEsK9B,cwB/K+B;EAC7B,UAAU;AzB68GhB;;AyBz9GA;EAeM,qB1BuDiB;EE4GnB,iBwBlKsC;AzB88G1C;;AyB99GA;EAmBI,eAAe;EACf,cAAc;EACd,cAAc;EACd,eAAe;EACf,aAAa;AzB+8GjB;;AyBt+GA;EAyBM,aAAa;AzBi9GnB;;AyB1+GA;;EA4BM,wB1BjBwB;ACo+G9B;;AyB/+GA;ExBkLI,oBwBpJwC;AzBq9G5C;;AyBn/GA;EAgCM,YAAY;EACZ,UAAU;AzBu9GhB;;AyBx/GA;EAmCQ,kBAAkB;AzBy9G1B;;AyB5/GA;EAuCM,qB1BnCwB;AC4/G9B;;AyBhgHA;EA6CQ,mB1BhCuB;ACu/G/B;;AyBpgHA;EA+CQ,mB1BlCuB;AC2/G/B;;AyBxgHA;EAkDU,qBfwDuB;AVk6GjC;;AyB5gHA;EAuDU,mD1B1CqB;ACmgH/B;;AyBhhHA;EA6CQ,qB1B7CqB;ACohH7B;;AyBphHA;EA+CQ,qB1B/CqB;ACwhH7B;;AyBxhHA;EAkDU,mBfwDuB;AVk7GjC;;AyB5hHA;EAuDU,gD1BvDmB;ACgiH7B;;AyBhiHA;EA6CQ,wB1BlCsB;ACyhH9B;;AyBpiHA;EA+CQ,wB1BpCsB;AC6hH9B;;AyBxiHA;EAkDU,qBfwDuB;AVk8GjC;;AyB5iHA;EAuDU,mD1B5CoB;ACqiH9B;;AyBhjHA;EA6CQ,qB1BzCsB;ACgjH9B;;AyBpjHA;EA+CQ,qB1B3CsB;ACojH9B;;AyBxjHA;EAkDU,qBfwDuB;AVk9GjC;;AyB5jHA;EAuDU,gD1BnDoB;AC4jH9B;;AyBhkHA;EA6CQ,qB1B3B0B;ACkjHlC;;AyBpkHA;EA+CQ,qB1B7B0B;ACsjHlC;;AyBxkHA;EAkDU,qBfwDuB;AVk+GjC;;AyB5kHA;EAuDU,iD1BrCwB;AC8jHlC;;AyBhlHA;EA6CQ,qB1BzB0B;ACgkHlC;;AyBplHA;EA+CQ,qB1B3B0B;ACokHlC;;AyBxlHA;EAkDU,qBfwDuB;AVk/GjC;;AyB5lHA;EAuDU,iD1BnCwB;AC4kHlC;;AyBhmHA;EA6CQ,qB1B1B0B;ACilHlC;;AyBpmHA;EA+CQ,qB1B5B0B;ACqlHlC;;AyBxmHA;EAkDU,qBfwDuB;AVkgHjC;;AyB5mHA;EAuDU,kD1BpCwB;AC6lHlC;;AyBhnHA;EA6CQ,qB1B5B0B;ACmmHlC;;AyBpnHA;EA+CQ,qB1B9B0B;ACumHlC;;AyBxnHA;EAkDU,qBfwDuB;AVkhHjC;;AyB5nHA;EAuDU,kD1BtCwB;AC+mHlC;;AyBhoHA;EA6CQ,qB1B7B0B;AConHlC;;AyBpoHA;EA+CQ,qB1B/B0B;ACwnHlC;;AyBxoHA;EAkDU,qBfwDuB;AVkiHjC;;AyB5oHA;EAuDU,mD1BvCwB;ACgoHlC;;AyBhpHA;EA6CQ,qB1BvByB;AC8nHjC;;AyBppHA;EA+CQ,qB1BzByB;ACkoHjC;;AyBxpHA;EAkDU,qBfwDuB;AVkjHjC;;AyB5pHA;EAuDU,kD1BjCuB;AC0oHjC;;AyBhqHA;E3ByCE,kBC0BgB;EDzBhB,kBCNc;ACioHhB;;AyBrqHA;E3B4CE,kBCVc;ACuoHhB;;AyBzqHA;E3B8CE,iBCba;AC4oHf;;AyB7qHA;EAkEM,gCAA8C;EAC9C,YAAY;AzB+mHlB;;AyBlrHA;EAqEI,WAAW;AzBinHf;;AyBtrHA;EAuEM,WAAW;AzBmnHjB;;AyB1rHA;EA2EM,aAAa;EACb,kBAAkB;ExB8GpB,cwB7G+B;EAC7B,YAAY;EACZ,eAAe;AzBmnHrB;;AyBlsHA;EAiFM,kB1B7CU;ACkqHhB;;AyBtsHA;EAmFM,kB1BjDU;ACwqHhB;;AyB1sHA;EAqFM,iB1BpDS;AC6qHf;;A0BjsHA;EAEE,oBAAoB;EACpB,aAAa;EACb,2BAA2B;EAC3B,kBAAkB;A1BmsHpB;;A0BxsHA;EAYQ,uB3BZuB;E2BavB,yBAAyB;EACzB,c3B3BqB;AC2tH7B;;A0B9sHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,c3BjCmB;ACiuH7B;;A0BptHA;EAwBU,yBAAyB;EACzB,+C3BzBqB;E2B0BrB,c3BvCmB;ACuuH7B;;A0B1tHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,c3B7CmB;AC6uH7B;;A0BhuHA;EAYQ,yB3BzBqB;E2B0BrB,yBAAyB;EACzB,Y3BduB;ACsuH/B;;A0BtuHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,Y3BpBqB;AC4uH/B;;A0B5uHA;EAwBU,yBAAyB;EACzB,4C3BtCmB;E2BuCnB,Y3B1BqB;ACkvH/B;;A0BlvHA;EA8BU,uBhB+DuB;EgB9DvB,yBAAyB;EACzB,Y3BhCqB;ACwvH/B;;A0BxvHA;EAYQ,4B3BdsB;E2BetB,yBAAyB;EACzB,yBhBmDa;AV6rHrB;;A0B9vHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,yBhB6CW;AVmsHrB;;A0BpwHA;EAwBU,yBAAyB;EACzB,+C3B3BoB;E2B4BpB,yBhBuCW;AVysHrB;;A0B1wHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,yBhBiCW;AV+sHrB;;A0BhxHA;EAYQ,yB3BrBsB;E2BsBtB,yBAAyB;EACzB,WhBqDQ;AVmtHhB;;A0BtxHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVytHhB;;A0B5xHA;EAwBU,yBAAyB;EACzB,4C3BlCoB;E2BmCpB,WhByCM;AV+tHhB;;A0BlyHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVquHhB;;A0BxyHA;EAYQ,yB3BP0B;E2BQ1B,yBAAyB;EACzB,WhBqDQ;AV2uHhB;;A0B9yHA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVivHhB;;A0BpzHA;EAwBU,yBAAyB;EACzB,6C3BpBwB;E2BqBxB,WhByCM;AVuvHhB;;A0B1zHA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AV6vHhB;;A0Bh0HA;EAYQ,yB3BL0B;E2BM1B,yBAAyB;EACzB,WhBqDQ;AVmwHhB;;A0Bt0HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVywHhB;;A0B50HA;EAwBU,yBAAyB;EACzB,6C3BlBwB;E2BmBxB,WhByCM;AV+wHhB;;A0Bl1HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVqxHhB;;A0Bx1HA;EAYQ,yB3BN0B;E2BO1B,yBAAyB;EACzB,WhBqDQ;AV2xHhB;;A0B91HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AViyHhB;;A0Bp2HA;EAwBU,yBAAyB;EACzB,8C3BnBwB;E2BoBxB,WhByCM;AVuyHhB;;A0B12HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AV6yHhB;;A0Bh3HA;EAYQ,yB3BR0B;E2BS1B,yBAAyB;EACzB,WhBqDQ;AVmzHhB;;A0Bt3HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVyzHhB;;A0B53HA;EAwBU,yBAAyB;EACzB,8C3BrBwB;E2BsBxB,WhByCM;AV+zHhB;;A0Bl4HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVq0HhB;;A0Bx4HA;EAYQ,yB3BT0B;E2BU1B,yBAAyB;EACzB,yBhBmDa;AV60HrB;;A0B94HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,yBhB6CW;AVm1HrB;;A0Bp5HA;EAwBU,yBAAyB;EACzB,+C3BtBwB;E2BuBxB,yBhBuCW;AVy1HrB;;A0B15HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,yBhBiCW;AV+1HrB;;A0Bh6HA;EAYQ,yB3BHyB;E2BIzB,yBAAyB;EACzB,WhBqDQ;AVm2HhB;;A0Bt6HA;EAkBU,yBhB2EuB;EgB1EvB,yBAAyB;EACzB,WhB+CM;AVy2HhB;;A0B56HA;EAwBU,yBAAyB;EACzB,8C3BhBuB;E2BiBvB,WhByCM;AV+2HhB;;A0Bl7HA;EA8BU,yBhB+DuB;EgB9DvB,yBAAyB;EACzB,WhBmCM;AVq3HhB;;A0Bx7HA;EAmCI,kB3BZY;ACq6HhB;;A0B57HA;EAqCI,e3BfS;AC06Hb;;A0Bh8HA;EAuCI,kB3BlBY;AC+6HhB;;A0Bp8HA;EA0CQ,eAAe;A1B85HvB;;A0Bx8HA;EA4CI,iB3BxBW;ACw7Hf;;A0B58HA;EA+CQ,eAAe;A1Bi6HvB;;A0Bh9HA;EAmDM,6BAA6B;EAC7B,0BAA0B;A1Bi6HhC;;A0Br9HA;EAsDM,4BAA4B;EAC5B,yBAAyB;A1Bm6H/B;;A0B19HA;EA0DQ,kB3BHI;ACu6HZ;;A0B99HA;EA4DQ,aAAa;A1Bs6HrB;;A0Bl+HA;EA+DM,sBAAsB;A1Bu6H5B;;A0Bt+HA;EAiEM,sBAAsB;EACtB,YAAY;EACZ,gBAAgB;A1By6HtB;;A0B5+HA;EAqEM,uBAAuB;A1B26H7B;;A0Bh/HA;EAuEM,aAAa;EACb,YAAY;A1B66HlB;;A0Br/HA;EA0EQ,eAAe;A1B+6HvB;;A0Bz/HA;EA6EQ,eAAe;A1Bg7HvB;;A0B7/HA;EAgFQ,eAAe;A1Bi7HvB;;A0BjgIA;EAmFQ,eAAe;A1Bk7HvB;;A0BrgIA;EAsFQ,0BAA4C;A1Bm7HpD;;A0BzgIA;EAwFQ,0B3BjCI;E2BkCJ,uBAAuB;A1Bq7H/B;;A0B9gIA;EA2FI,uBAAuB;A1Bu7H3B;;A0BlhIA;EA8FM,WAAW;A1Bw7HjB;;A0BthIA;EAgGM,YAAY;EACZ,eAAe;A1B07HrB;;A0B3hIA;EAmGI,yBAAyB;A1B47H7B;;A0B/hIA;EAqGM,0BAA4C;A1B87HlD;;A0BniIA;EAuGM,0B3BhDM;E2BiDN,2BAA2B;EAC3B,SAAS;A1Bg8Hf;;A0B97HA;EACE,oBAAoB;EACpB,aAAa;EACb,eAAe;EACf,2BAA2B;EAC3B,gBAAgB;EAChB,kBAAkB;A1Bi8HpB;;A0Bv8HA;EASM,yBhBvB2B;EgBwB3B,c3B9HwB;ACgkI9B;;A0B58HA;EAYM,qBhB1B2B;AV89HjC;;A0Bh9HA;EAeM,yBhB7B2B;EgB8B3B,c3BpIwB;ACykI9B;;A0Br9HA;EAkBM,qBhBhC2B;AVu+HjC;;A0Br8HA;EACE,YAAY;EACZ,OAAO;EACP,UAAU;EACV,aAAa;EACb,kBAAkB;EAClB,MAAM;EACN,WAAW;A1Bw8Hb;;A0Bt8HA;;EAGE,qB3BhJ4B;E2BiJ5B,kB3BrFU;E2BsFV,cAAc;EACd,iBAAiB;EACjB,kBAAkB;EAClB,mBAAmB;A1Bw8HrB;;A0Bt8HA;EACE,4B3BrJ4B;E2BsJ5B,c3B5J4B;ACqmI9B;;A0Bv8HA;EACE,qB3B5J4B;E2B6J5B,mBA9J4B;EA+J5B,2BA9JoC;EA+JpC,cAAc;EACd,eA/JwB;EAgKxB,gBAAgB;EAChB,mBAAmB;EACnB,uBAAuB;A1B08HzB;;A0Bx8HA;EACE,mBAAmB;EACnB,aAAa;EACb,WAAW;EACX,uBAAuB;EzBCrB,mByBAmC;EACrC,UAAU;A1B28HZ;;A0Bj9HA;EAQI,eAAe;A1B68HnB;;A2B7nIA;EACE,c5BF4B;E4BG5B,cAAc;EACd,e5B2BW;E4B1BX,gB5BiCe;AC+lIjB;;A2BpoIA;EAMI,oBAAoB;A3BkoIxB;;A2BxoIA;EASI,kB5BsBY;AC6mIhB;;A2B5oIA;EAWI,kB5BkBY;ACmnIhB;;A2BhpIA;EAaI,iB5BeW;ACwnIf;;A2BroIA;EACE,cAAc;EACd,kB5Bcc;E4Bbd,mBAAmB;A3BwoIrB;;A2B3oIA;EAOM,Y5BdyB;ACspI/B;;A2B/oIA;EAOM,c5B3BuB;ACuqI7B;;A2BnpIA;EAOM,iB5BhBwB;ACgqI9B;;A2BvpIA;EAOM,c5BvBwB;AC2qI9B;;A2B3pIA;EAOM,c5BT4B;ACiqIlC;;A2B/pIA;EAOM,c5BP4B;ACmqIlC;;A2BnqIA;EAOM,c5BR4B;ACwqIlC;;A2BvqIA;EAOM,c5BV4B;AC8qIlC;;A2B3qIA;EAOM,c5BX4B;ACmrIlC;;A2B/qIA;EAOM,c5BL2B;ACirIjC;;A2BxqIA;EAEI,sBAAsB;A3B0qI1B;;A2B5qIA;EAKI,aAAa;EACb,2BAA2B;A3B2qI/B;;A2BjrIA;E1BmJI,kB0B1IwC;A3B4qI5C;;A2BrrIA;;;EAcU,gBAAgB;A3B6qI1B;;A2B3rIA;;;EAoBY,6BAA6B;EAC7B,0BAA0B;A3B6qItC;;A2BlsIA;;;EA8BY,4BAA4B;EAC5B,yBAAyB;A3B0qIrC;;A2BzsIA;;;;;EAyCY,UAAU;A3BwqItB;;A2BjtIA;;;;;;;;;EA8CY,UAAU;A3B+qItB;;A2B7tIA;;;;;;;;;EAgDc,UAAU;A3ByrIxB;;A2BzuIA;EAkDQ,YAAY;EACZ,cAAc;A3B2rItB;;A2B9uIA;EAqDM,uBAAuB;A3B6rI7B;;A2BlvIA;EAuDM,yBAAyB;A3B+rI/B;;A2BtvIA;EA0DQ,YAAY;EACZ,cAAc;A3BgsItB;;A2B3vIA;EA6DI,aAAa;EACb,2BAA2B;A3BksI/B;;A2BhwIA;EAgEM,cAAc;A3BosIpB;;A2BpwIA;EAkEQ,gBAAgB;E1BiFpB,qB0BhF2C;A3BssI/C;;A2BzwIA;EAqEQ,YAAY;EACZ,cAAc;A3BwsItB;;A2B9wIA;EAwEM,uBAAuB;A3B0sI7B;;A2BlxIA;EA0EM,yBAAyB;A3B4sI/B;;A2BtxIA;EA4EM,eAAe;A3B8sIrB;;A2B1xIA;EAgFU,sBAAsB;A3B8sIhC;;A2B9xIA;EAkFQ,uBAAuB;A3BgtI/B;;A2BlyIA;EAoFQ,gBAAgB;A3BktIxB;;AC7tIE;E0BzEF;IAuFM,aAAa;E3BotIjB;AACF;;A2BntIA;EAEI,kBAAkB;A3BqtItB;;AC3uIE;E0BoBF;IAII,qBAAqB;E3BwtIvB;AACF;;AC7uIE;E0BgBF;IAMI,aAAa;IACb,YAAY;IACZ,cAAc;I1BkDd,oB0BjDsC;IACtC,iBAAiB;E3B4tInB;E2BtuIF;IAYM,kB5BhGU;I4BiGV,oBAAoB;E3B6tIxB;E2B1uIF;IAeM,oBAAoB;E3B8tIxB;E2B7uIF;IAiBM,kB5BvGU;I4BwGV,oBAAoB;E3B+tIxB;E2BjvIF;IAoBM,iB5B3GS;I4B4GT,oBAAoB;E3BguIxB;AACF;;A2B/tIA;EAEI,gBAAgB;A3BiuIpB;;AC1wIE;E0BuCF;IAII,aAAa;IACb,aAAa;IACb,YAAY;IACZ,cAAc;E3BouIhB;E2B3uIF;IASM,gBAAgB;E3BquIpB;E2B9uIF;IAWM,cAAc;E3BsuIlB;E2BjvIF;IAaQ,YAAY;E3BuuIlB;E2BpvIF;I1BmCI,qB0BpB2C;E3BwuI7C;AACF;;A2BvuIA;EACE,sBAAsB;EACtB,WAAW;EACX,e5BhIW;E4BiIX,kBAAkB;EAClB,mBAAmB;A3B0uIrB;;A2B/uIA;;;EAaU,c5BxKoB;ACg5I9B;;A2BrvIA;;;EAeQ,kB5B3IQ;ACu3IhB;;A2B3vIA;;;EAiBQ,kB5B/IQ;AC+3IhB;;A2BjwIA;;;EAmBQ,iB5BlJO;ACs4If;;A2BvwIA;EAqBM,c5B7KwB;E4B8KxB,a7BjLgB;E6BkLhB,oBAAoB;EACpB,kBAAkB;EAClB,MAAM;EACN,Y7BrLgB;E6BsLhB,UAAU;A3BsvIhB;;A2BjxIA;;EA+BM,mB7B1LgB;AEi7ItB;;A2BtxIA;EAiCM,OAAO;A3ByvIb;;A2B1xIA;;EAqCM,oB7BhMgB;AE07ItB;;A2B/xIA;EAuCM,QAAQ;A3B4vId;;A2BnyIA;EA2CM,6BAA6B;E1BjB/B,c0BkB+B;EAC7B,YAAY;EACZ,UAAU;A3B4vIhB;;A2B1yIA;EAgDM,kB5B5KU;AC06IhB;;A2B9yIA;EAkDM,kB5BhLU;ACg7IhB;;A2BlzIA;EAoDM,iB5BnLS;ACq7If;;A4Bx9IA,qBAAA;ACWA;EAGE,e9BuBW;E8BtBX,mBAAmB;A7B+8IrB;;A6Bn9IA;EAMI,mBAAmB;EACnB,c9BI8B;E8BH9B,aAAa;EACb,uBAAuB;EACvB,iBAduC;A7B+9I3C;;A6B39IA;EAYM,c9BjBwB;ACo+I9B;;A6B/9IA;EAcI,mBAAmB;EACnB,aAAa;A7Bq9IjB;;A6Bp+IA;E5ByKI,e4BxJoC;A7Bu9IxC;;A6Bx+IA;EAoBQ,c9BzBsB;E8B0BtB,eAAe;EACf,oBAAoB;A7Bw9I5B;;A6B9+IA;EAwBM,c9B1BwB;E8B2BxB,iBAAiB;A7B09IvB;;A6Bn/IA;;EA4BI,uBAAuB;EACvB,aAAa;EACb,eAAe;EACf,2BAA2B;A7B49I/B;;A6B3/IA;E5ByKI,mB4BvIuC;A7B69I3C;;A6B//IA;E5ByKI,kB4BrIuC;A7B+9I3C;;A6BngJA;;EAyCM,uBAAuB;A7B+9I7B;;A6BxgJA;;EA6CM,yBAAyB;A7Bg+I/B;;A6B7gJA;EAgDI,kB9BrBY;ACs/IhB;;A6BjhJA;EAkDI,kB9BzBY;AC4/IhB;;A6BrhJA;EAoDI,iB9B5BW;ACigJf;;A6BzhJA;EAwDM,iBAAiB;A7Bq+IvB;;A6B7hJA;EA2DM,iBAAiB;A7Bs+IvB;;A6BjiJA;EA8DM,iBAAiB;A7Bu+IvB;;A6BriJA;EAiEM,iBAAiB;A7Bw+IvB;;A8B9hJA;EACE,uB/BR6B;E+BS7B,sBAnBmB;EAoBnB,0F/BvB2B;E+BwB3B,c/BnB4B;E+BoB5B,eAAe;EACf,kBAAkB;A9BiiJpB;;A8B9hJE;EACE,+BA3BiB;EA4BjB,gCA5BiB;A9B6jJrB;;A8BhiJE;EACE,kCA9BiB;EA+BjB,mCA/BiB;A9BkkJrB;;A8BjiJA;EAEE,6BAjCwC;EAkCxC,oBAAoB;EACpB,kD/BxC2B;E+ByC3B,aAAa;A9BmiJf;;A8BjiJA;EACE,mBAAmB;EACnB,c/BzC4B;E+B0C5B,aAAa;EACb,YAAY;EACZ,gB/BNe;E+BOf,qBA1CgC;A9B8kJlC;;A8B1iJA;EAQI,uBAAuB;A9BsiJ3B;;A8BpiJA;E7BqBE,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,mBAAmB;EACnB,oBAAoB;EACpB,cAAc;EACd,SAAS;EACT,UAAU;E6B5BV,mBAAmB;EACnB,eAAe;EACf,aAAa;EACb,uBAAuB;EACvB,qBApDgC;A9BomJlC;;A8B9iJA;EACE,cAAc;EACd,kBAAkB;A9BijJpB;;A8BnjJA;EAKM,+BA/De;EAgEf,gCAhEe;A9BknJrB;;A8BxjJA;EASM,kCAnEe;EAoEf,mCApEe;A9BunJrB;;A8BjjJA;EAEE,6BAhEyC;EAiEzC,eAhE2B;A9BmnJ7B;;A8BjjJA;EAEE,6BAlEwC;EAmExC,6B/BxE6B;E+ByE7B,oBAAoB;EACpB,aAAa;A9BmjJf;;A8BjjJA;EACE,mBAAmB;EACnB,aAAa;EACb,aAAa;EACb,YAAY;EACZ,cAAc;EACd,uBAAuB;EACvB,gBA5E2B;A9BgoJ7B;;A8B3jJA;E7B6FI,+BFzK2B;AC2oJ/B;;A8BljJA;EAEI,qB/BtDkB;AC0mJtB;;A+BroJA;EACE,oBAAoB;EACpB,kBAAkB;EAClB,mBAAmB;A/BwoJrB;;A+B3oJA;EAOM,cAAc;A/BwoJpB;;A+B/oJA;EAUM,UAAU;EACV,QAAQ;A/ByoJd;;A+BppJA;EAcM,YAAY;EACZ,mBA9BuB;EA+BvB,oBAAoB;EACpB,SAAS;A/B0oJf;;A+BxoJA;EACE,aAAa;E9BmJX,O8BlJqB;EACvB,gBAzC6B;EA0C7B,gBAtC2B;EAuC3B,kBAAkB;EAClB,SAAS;EACT,WApCqB;A/B+qJvB;;A+BzoJA;EACE,uBhCnC6B;EgCoC7B,kBhCmBU;EgClBV,0FhClD2B;EgCmD3B,sBA9CsC;EA+CtC,mBA9CmC;A/B0rJrC;;Ae9qJgB;EgBqCd,chClD4B;EgCmD5B,cAAc;EACd,mBAAmB;EACnB,gBAAgB;EAChB,sBAAsB;EACtB,kBAAkB;A/B6oJpB;;A+B3oJA;;E9BoHI,mB8BlHmC;EACrC,mBAAmB;EACnB,mBAAmB;EACnB,WAAW;A/B8oJb;;A+BnpJA;;EAOI,4BhC1D0B;EgC2D1B,chCtEyB;ACutJ7B;;A+BzpJA;;EAUI,yBhCpD8B;EgCqD9B,WrBOY;AV6oJhB;;A+BlpJA;EACE,yBhCnE6B;EgCoE7B,YAAY;EACZ,cAAc;EACd,WAAW;EACX,gBAAgB;A/BqpJlB;;AgCnuJA;EAEE,mBAAmB;EACnB,8BAA8B;AhCquJhC;;AgCxuJA;EAKI,kBjC6DQ;AC0qJZ;;AgC5uJA;EAOI,qBAAqB;EACrB,mBAAmB;AhCyuJvB;;AgCjvJA;EAWI,aAAa;AhC0uJjB;;AgCrvJA;;EAcM,aAAa;AhC4uJnB;;AgC1vJA;EAgBM,aAAa;AhC8uJnB;;AgC9vJA;EAmBQ,gBAAgB;E/B6JpB,qB+BlLuC;AhCqwJ3C;;AgCnwJA;EAsBQ,YAAY;AhCivJpB;;ACjqJE;E+BtGF;IAyBI,aAAa;EhCmvJf;EgC5wJF;IA4BQ,YAAY;EhCmvJlB;AACF;;AgClvJA;EACE,mBAAmB;EACnB,aAAa;EACb,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,uBAAuB;AhCqvJzB;;AgC3vJA;;EASI,gBAAgB;AhCuvJpB;;AC5rJE;E+BpEF;IAaM,sBA7CqC;EhCqyJzC;AACF;;AgCvvJA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AhC0vJhB;;AgC9vJA;;EAQM,YAAY;AhC2vJlB;;AC1sJE;E+BzDF;;I/BmII,qB+BlLuC;EhCwzJzC;AACF;;AgC5vJA;EACE,mBAAmB;EACnB,2BAA2B;AhC+vJ7B;;AC1tJE;E+BvCF;IAMM,kBAAkB;EhCgwJtB;AACF;;AC5tJE;E+B3CF;IAQI,aAAa;EhCowJf;AACF;;AgCnwJA;EACE,mBAAmB;EACnB,yBAAyB;AhCswJ3B;;ACvuJE;E+BjCF;IAKI,aAAa;EhCwwJf;AACF;;AiC50JA;EACE,uBAAuB;EACvB,aAAa;EACb,mBAAmB;AjC+0JrB;;AiCl1JA;EAKI,sBAV2B;AjC21J/B;;AiCt1JA;EAOI,8ClCR0B;EkCS1B,aAAa;EACb,oBAb2B;AjCg2J/B;;AiC51JA;;EAYM,qBAfgC;AjCo2JtC;;AiCj2JA;EAcM,mBAhBwB;AjCu2J9B;;AiCr2JA;EAgBQ,kBAlBsB;AjC22J9B;;AiCz2JA;EAkBI,8ClCnB0B;EkCoB1B,gBA1BgB;EA2BhB,iBA3BgB;AjCs3JpB;;AiC/2JA;EAwBM,kBA9BsB;EA+BtB,mBA/BsB;AjC03J5B;;AiCz1JA;;EAEE,gBAAgB;EAChB,YAAY;EACZ,cAAc;AjC41JhB;;AiC11JA;EhCwII,kBgChLgB;AjCs4JpB;;AiC31JA;EhCqII,iBgChLgB;AjC04JpB;;AiC51JA;EACE,gBAAgB;EAChB,YAAY;EACZ,cAAc;EACd,mBAAmB;AjC+1JrB;;AC/yJE;EgCpDF;IAQI,gBAAgB;EjCg2JlB;AACF;;AkCv4JA;EACE,enCgBW;AC03Jb;;AkC34JA;EAII,kBnCcY;AC63JhB;;AkC/4JA;EAMI,kBnCUY;ACm4JhB;;AkCn5JA;EAQI,iBnCOW;ACw4Jf;;AkC74JA;EACE,iBArB0B;AlCq6J5B;;AkCj5JA;EAGI,kBnCoCc;EmCnCd,cnC3B0B;EmC4B1B,cAAc;EACd,qBAzBiC;AlC26JrC;;AkCx5JA;EAQM,4BnCzBwB;EmC0BxB,cnCjCwB;ACq7J9B;;AkC75JA;EAYM,yBnCpB4B;EmCqB5B,WxBuCU;AV82JhB;;AkCl6JA;EjCsJI,8BF1K0B;EmCqCxB,cAnC0B;EjCwK5B,oBiCvKkC;AlCy7JtC;;AkCp5JA;EACE,cnC3C4B;EmC4C5B,iBApC2B;EAqC3B,qBApC+B;EAqC/B,yBAAyB;AlCu5J3B;;AkC35JA;EAMI,eAtCoB;AlC+7JxB;;AkC/5JA;EAQI,kBAxCoB;AlCm8JxB;;AmC97JA;EAEE,4BpCZ4B;EoCa5B,kBpC4CU;EoC3CV,epCUW;ACs7Jb;;AmCp8JA;EAMI,mBAAmB;AnCk8JvB;;AmCx8JA;EAQI,mBAAmB;EACnB,0BAA0B;AnCo8J9B;;AmC78JA;EAYI,kBpCGY;ACk8JhB;;AmCj9JA;EAcI,kBpCDY;ACw8JhB;;AmCr9JA;EAgBI,iBpCJW;AC68Jf;;AmCz9JA;EAsCM,uBAH+C;AnC07JrD;;AmC79JA;EAwCQ,uBpChDuB;EoCiDvB,cpC9DqB;ACu/J7B;;AmCl+JA;EA2CQ,mBpCnDuB;AC8+J/B;;AmCt+JA;EAsCM,yBAH+C;AnCu8JrD;;AmC1+JA;EAwCQ,yBpC7DqB;EoC8DrB,YpCjDuB;ACu/J/B;;AmC/+JA;EA2CQ,qBpChEqB;ACwgK7B;;AmCn/JA;EAsCM,yBAH+C;AnCo9JrD;;AmCv/JA;EAwCQ,4BpClDsB;EoCmDtB,yBzBgBa;AVm8JrB;;AmC5/JA;EA2CQ,wBpCrDsB;AC0gK9B;;AmChgKA;EAsCM,yBAH+C;AnCi+JrD;;AmCpgKA;EAwCQ,yBpCzDsB;EoC0DtB,WzBkBQ;AV88JhB;;AmCzgKA;EA2CQ,qBpC5DsB;AC8hK9B;;AmC7gKA;EAsCM,yBzB4B0C;AV+8JhD;;AmCjhKA;EAwCQ,yBpC3C0B;EoC4C1B,WzBkBQ;AV29JhB;;AmCthKA;EA2CQ,qBpC9C0B;EoC+C1B,czB8B6D;AVi9JrE;;AmC3hKA;EAsCM,yBzB4B0C;AV69JhD;;AmC/hKA;EAwCQ,yBpCzC0B;EoC0C1B,WzBkBQ;AVy+JhB;;AmCpiKA;EA2CQ,qBpC5C0B;EoC6C1B,czB8B6D;AV+9JrE;;AmCziKA;EAsCM,yBzB4B0C;AV2+JhD;;AmC7iKA;EAwCQ,yBpC1C0B;EoC2C1B,WzBkBQ;AVu/JhB;;AmCljKA;EA2CQ,qBpC7C0B;EoC8C1B,czB8B6D;AV6+JrE;;AmCvjKA;EAsCM,yBzB4B0C;AVy/JhD;;AmC3jKA;EAwCQ,yBpC5C0B;EoC6C1B,WzBkBQ;AVqgKhB;;AmChkKA;EA2CQ,qBpC/C0B;EoCgD1B,czB8B6D;AV2/JrE;;AmCrkKA;EAsCM,yBzB4B0C;AVugKhD;;AmCzkKA;EAwCQ,yBpC7C0B;EoC8C1B,yBzBgBa;AVqhKrB;;AmC9kKA;EA2CQ,qBpChD0B;EoCiD1B,czB8B6D;AVygKrE;;AmCnlKA;EAsCM,yBzB4B0C;AVqhKhD;;AmCvlKA;EAwCQ,yBpCvCyB;EoCwCzB,WzBkBQ;AViiKhB;;AmC5lKA;EA2CQ,qBpC1CyB;EoC2CzB,czB8B6D;AVuhKrE;;AmCnjKA;EACE,mBAAmB;EACnB,yBpChE4B;EoCiE5B,0BAAgE;EAChE,WzBSc;EyBRd,aAAa;EACb,gBpC/Be;EoCgCf,8BAA8B;EAC9B,iBAAiB;EACjB,mBAtEiC;EAuEjC,kBAAkB;AnCsjKpB;;AmChkKA;EAYI,YAAY;EACZ,cAAc;ElCkGd,mBkCjGsC;AnCwjK1C;;AmCtkKA;EAgBI,eAjEgC;EAkEhC,yBAAyB;EACzB,0BAA0B;AnC0jK9B;;AmCxjKA;EACE,qBpChF4B;EoCiF5B,kBpCrBU;EoCsBV,mBAAmB;EACnB,uBAjFmC;EAkFnC,cpCvF4B;EoCwF5B,qBAjFiC;AnC4oKnC;;AmCjkKA;;EASI,uBpCnF2B;ACgpK/B;;AmCtkKA;EAWI,6BAlFgD;AnCipKpD;;AoCjoKA;EAEE,mBAAmB;EACnB,aAAa;EACb,sBAAsB;EACtB,uBAAuB;EACvB,gBAAgB;EAChB,eAAe;EACf,WAxCU;ApC2qKZ;;AoC3oKA;EAWI,aAAa;ApCooKjB;;AoCloKA;EAEE,wCrC/C2B;ACmrK7B;;AoCloKA;;EAEE,cA9CgC;EA+ChC,+BAA0D;EAC1D,cAAc;EACd,kBAAkB;EAClB,WAAW;ApCqoKb;;ACpmKE;EmCvCF;;IASI,cAAc;IACd,8BAA0D;IAC1D,YAxDuB;EpCgsKzB;AACF;;AoCvoKA;EAEE,gBAAgB;EAChB,YAxD2B;EAyD3B,eAAe;EnCwHb,WmChLoB;EA0DtB,SAzDoB;EA0DpB,WA5D2B;ApCqsK7B;;AoCvoKA;EACE,aAAa;EACb,sBAAsB;EACtB,8BAAgD;EAChD,gBAAgB;EAChB,uBAAuB;ApC0oKzB;;AoCxoKA;;EAEE,mBAAmB;EACnB,4BrCtE4B;EqCuE5B,aAAa;EACb,cAAc;EACd,2BAA2B;EAC3B,aApE4B;EAqE5B,kBAAkB;ApC2oKpB;;AoCzoKA;EACE,gCrCjF4B;EqCkF5B,2BrCrBgB;EqCsBhB,4BrCtBgB;ACkqKlB;;AoC1oKA;EACE,crC1F4B;EqC2F5B,YAAY;EACZ,cAAc;EACd,iBrChEa;EqCiEb,cA7E8B;ApC0tKhC;;AoC3oKA;EACE,8BrChCgB;EqCiChB,+BrCjCgB;EqCkChB,6BrC/F4B;AC6uK9B;;AoCjpKA;EnC8EI,mBmCxEuC;ApC+oK3C;;AoC7oKA;EnC3CE,iCAAiC;EmC6CjC,uBrCjG6B;EqCkG7B,YAAY;EACZ,cAAc;EACd,cAAc;EACd,aAtF4B;ApCsuK9B;;AqC1sKA;EACE,uBtC5C6B;EsC6C7B,mBAvDqB;EAwDrB,kBAAkB;EAClB,WAtDW;ArCmwKb;;AqCjtKA;EASM,uBtCpDyB;EsCqDzB,ctClEuB;AC8wK7B;;AqCttKA;;EAcU,ctCtEmB;ACmxK7B;;AqC3tKA;;;;EAoBY,yB3B8BqB;E2B7BrB,ctC7EiB;AC2xK7B;;AqCnuKA;EAwBY,qBtChFiB;AC+xK7B;;AqCvuKA;EA0BQ,ctClFqB;ACmyK7B;;AC3sKE;EoChCF;;;;IAgCY,ctCxFiB;EC2yK3B;EqCnvKF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,ctC/Fe;ECwzK3B;EqChwKF;;IA0Cc,qBtClGe;EC4zK3B;EqCpwKF;;;IA8CU,yB3BIuB;I2BHvB,ctCvGmB;ECk0K3B;EqC1wKF;IAmDc,uBtC9FiB;IsC+FjB,ctC5Ge;ECs0K3B;AACF;;AqC/wKA;EASM,yBtCjEuB;EsCkEvB,YtCrDyB;AC+zK/B;;AqCpxKA;;EAcU,YtCzDqB;ACo0K/B;;AqCzxKA;;;;EAoBY,uB3B8BqB;E2B7BrB,YtChEmB;AC40K/B;;AqCjyKA;EAwBY,mBtCnEmB;ACg1K/B;;AqCryKA;EA0BQ,YtCrEuB;ACo1K/B;;ACzwKE;EoChCF;;;;IAgCY,YtC3EmB;EC41K7B;EqCjzKF;;;;;;;;;;IAsCc,uB3BYmB;I2BXnB,YtClFiB;ECy2K7B;EqC9zKF;;IA0Cc,mBtCrFiB;EC62K7B;EqCl0KF;;;IA8CU,uB3BIuB;I2BHvB,YtC1FqB;ECm3K7B;EqCx0KF;IAmDc,yBtC3Ge;IsC4Gf,YtC/FiB;ECu3K7B;AACF;;AqC70KA;EASM,4BtCtDwB;EsCuDxB,yB3BYe;AV4zKrB;;AqCl1KA;;EAcU,yB3BQW;AVi0KrB;;AqCv1KA;;;;EAoBY,yB3B8BqB;E2B7BrB,yB3BCS;AVy0KrB;;AqC/1KA;EAwBY,gC3BFS;AV60KrB;;AqCn2KA;EA0BQ,yB3BJa;AVi1KrB;;ACv0KE;EoChCF;;;;IAgCY,yB3BVS;EVy1KnB;EqC/2KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,yB3BjBO;EVs2KnB;EqC53KF;;IA0Cc,gC3BpBO;EV02KnB;EqCh4KF;;;IA8CU,yB3BIuB;I2BHvB,yB3BzBW;EVg3KnB;EqCt4KF;IAmDc,4BtChGgB;IsCiGhB,yB3B9BO;EVo3KnB;AACF;;AqC34KA;EASM,yBtC7DwB;EsC8DxB,W3BcU;AVw3KhB;;AqCh5KA;;EAcU,W3BUM;AV63KhB;;AqCr5KA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVq4KhB;;AqC75KA;EAwBY,kB3BAI;AVy4KhB;;AqCj6KA;EA0BQ,W3BFQ;AV64KhB;;ACr4KE;EoChCF;;;;IAgCY,W3BRI;EVq5Kd;EqC76KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVk6Kd;EqC17KF;;IA0Cc,kB3BlBE;EVs6Kd;EqC97KF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EV46Kd;EqCp8KF;IAmDc,yBtCvGgB;IsCwGhB,W3B5BE;EVg7Kd;AACF;;AqCz8KA;EASM,yBtC/C4B;EsCgD5B,W3BcU;AVs7KhB;;AqC98KA;;EAcU,W3BUM;AV27KhB;;AqCn9KA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVm8KhB;;AqC39KA;EAwBY,kB3BAI;AVu8KhB;;AqC/9KA;EA0BQ,W3BFQ;AV28KhB;;ACn8KE;EoChCF;;;;IAgCY,W3BRI;EVm9Kd;EqC3+KF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVg+Kd;EqCx/KF;;IA0Cc,kB3BlBE;EVo+Kd;EqC5/KF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EV0+Kd;EqClgLF;IAmDc,yBtCzFoB;IsC0FpB,W3B5BE;EV8+Kd;AACF;;AqCvgLA;EASM,yBtC7C4B;EsC8C5B,W3BcU;AVo/KhB;;AqC5gLA;;EAcU,W3BUM;AVy/KhB;;AqCjhLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVigLhB;;AqCzhLA;EAwBY,kB3BAI;AVqgLhB;;AqC7hLA;EA0BQ,W3BFQ;AVygLhB;;ACjgLE;EoChCF;;;;IAgCY,W3BRI;EVihLd;EqCziLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV8hLd;EqCtjLF;;IA0Cc,kB3BlBE;EVkiLd;EqC1jLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVwiLd;EqChkLF;IAmDc,yBtCvFoB;IsCwFpB,W3B5BE;EV4iLd;AACF;;AqCrkLA;EASM,yBtC9C4B;EsC+C5B,W3BcU;AVkjLhB;;AqC1kLA;;EAcU,W3BUM;AVujLhB;;AqC/kLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AV+jLhB;;AqCvlLA;EAwBY,kB3BAI;AVmkLhB;;AqC3lLA;EA0BQ,W3BFQ;AVukLhB;;AC/jLE;EoChCF;;;;IAgCY,W3BRI;EV+kLd;EqCvmLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV4lLd;EqCpnLF;;IA0Cc,kB3BlBE;EVgmLd;EqCxnLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVsmLd;EqC9nLF;IAmDc,yBtCxFoB;IsCyFpB,W3B5BE;EV0mLd;AACF;;AqCnoLA;EASM,yBtChD4B;EsCiD5B,W3BcU;AVgnLhB;;AqCxoLA;;EAcU,W3BUM;AVqnLhB;;AqC7oLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AV6nLhB;;AqCrpLA;EAwBY,kB3BAI;AVioLhB;;AqCzpLA;EA0BQ,W3BFQ;AVqoLhB;;AC7nLE;EoChCF;;;;IAgCY,W3BRI;EV6oLd;EqCrqLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EV0pLd;EqClrLF;;IA0Cc,kB3BlBE;EV8pLd;EqCtrLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVoqLd;EqC5rLF;IAmDc,yBtC1FoB;IsC2FpB,W3B5BE;EVwqLd;AACF;;AqCjsLA;EASM,yBtCjD4B;EsCkD5B,yB3BYe;AVgrLrB;;AqCtsLA;;EAcU,yB3BQW;AVqrLrB;;AqC3sLA;;;;EAoBY,yB3B8BqB;E2B7BrB,yB3BCS;AV6rLrB;;AqCntLA;EAwBY,gC3BFS;AVisLrB;;AqCvtLA;EA0BQ,yB3BJa;AVqsLrB;;AC3rLE;EoChCF;;;;IAgCY,yB3BVS;EV6sLnB;EqCnuLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,yB3BjBO;EV0tLnB;EqChvLF;;IA0Cc,gC3BpBO;EV8tLnB;EqCpvLF;;;IA8CU,yB3BIuB;I2BHvB,yB3BzBW;EVouLnB;EqC1vLF;IAmDc,yBtC3FoB;IsC4FpB,yB3B9BO;EVwuLnB;AACF;;AqC/vLA;EASM,yBtC3C2B;EsC4C3B,W3BcU;AV4uLhB;;AqCpwLA;;EAcU,W3BUM;AVivLhB;;AqCzwLA;;;;EAoBY,yB3B8BqB;E2B7BrB,W3BGI;AVyvLhB;;AqCjxLA;EAwBY,kB3BAI;AV6vLhB;;AqCrxLA;EA0BQ,W3BFQ;AViwLhB;;ACzvLE;EoChCF;;;;IAgCY,W3BRI;EVywLd;EqCjyLF;;;;;;;;;;IAsCc,yB3BYmB;I2BXnB,W3BfE;EVsxLd;EqC9yLF;;IA0Cc,kB3BlBE;EV0xLd;EqClzLF;;;IA8CU,yB3BIuB;I2BHvB,W3BvBM;EVgyLd;EqCxzLF;IAmDc,yBtCrFmB;IsCsFnB,W3B5BE;EVoyLd;AACF;;AqC7zLA;EAsDI,oBAAoB;EACpB,aAAa;EACb,mBA7GmB;EA8GnB,WAAW;ArC2wLf;;AqCp0LA;EA2DI,gCtCxG0B;ACq3L9B;;AqCx0LA;EALE,OAAO;EACP,eAAe;EACf,QAAQ;EACR,WA/CiB;ArCg4LnB;;AqC/0LA;EAgEI,SAAS;ArCmxLb;;AqCn1LA;EAkEM,iCtC/GwB;ACo4L9B;;AqCv1LA;EAoEI,MAAM;ArCuxLV;;AqCrxLA;;EAGI,oBA9HmB;ArCq5LvB;;AqC1xLA;;EAKI,uBAhImB;ArC05LvB;;AqCxxLA;;EAEE,oBAAoB;EACpB,aAAa;EACb,cAAc;EACd,mBAvIqB;ArCk6LvB;;AqCzxLA;EAIM,6BAA6B;ArCyxLnC;;AqCvxLA;EpCjFE,iCAAiC;EoCmFjC,gBAAgB;EAChB,gBAAgB;EAChB,kBAAkB;ArC0xLpB;;AqCxxLA;EAEE,ctCrJ4B;EEoB5B,qBAAqB;EACrB,wBAAwB;EACxB,gBAAgB;EAChB,gBAAgB;EAChB,YAAY;EACZ,eAAe;EACf,cAAc;EACd,eoC7BqB;EpC8BrB,kBAAkB;EAClB,coC/BqB;EpC+KnB,iBoCtBkC;ArCmyLtC;;AC55LE;EACE,8BAA8B;EAC9B,cAAc;EACd,WAAW;EACX,qBAAqB;EACrB,kBAAkB;EAClB,wBAAwB;EACxB,yBF6BQ;EE5BR,yDAAyD;EACzD,oCFsBa;EErBb,WAAW;AD+5Lf;;AC95LI;EACE,oBAAoB;ADi6L1B;;ACh6LI;EACE,oBAAoB;ADm6L1B;;ACl6LI;EACE,oBAAoB;ADq6L1B;;ACp6LE;EACE,qCAAiC;ADu6LrC;;ACn6LM;EACE,wCAAwC;ADs6LhD;;ACr6LM;EACE,UAAU;ADw6LlB;;ACv6LM;EACE,0CAA0C;AD06LlD;;AqC10LA;EACE,aAAa;ArC60Lf;;AqC30LA;;EAEE,ctC9J4B;EsC+J5B,cAAc;EACd,gBAAgB;EAChB,uBAAuB;EACvB,kBAAkB;ArC80LpB;;AqCp1LA;;EASM,qBAAqB;EACrB,sBAAsB;ArCg1L5B;;AqC90LA;;EAEE,eAAe;ArCi1LjB;;AqCn1LA;;;;;EAOI,yBtCxK0B;EsCyK1B,ctCjK8B;ACq/LlC;;AqCl1LA;EACE,YAAY;EACZ,cAAc;ArCq1LhB;;AqCv1LA;EAII,mBA7KgC;ArCogMpC;;AqC31LA;EAMI,UAAU;ArCy1Ld;;AqC/1LA;EAQI,YAAY;EACZ,cAAc;ArC21LlB;;AqCp2LA;EAWI,oCAAoC;EACpC,mBAhMmB;EAiMnB,kCAAkC;ArC61LtC;;AqC12LA;EAgBM,6BArLyC;EAsLzC,4BtCpL4B;ACkhMlC;;AqC/2LA;EAmBM,6BArL0C;EAsL1C,4BtCvL4B;EsCwL5B,0BArLuC;EAsLvC,wBArLqC;EAsLrC,ctC1L4B;EsC2L5B,kCAAwE;ArCg2L9E;;AqC91LA;EACE,YAAY;EACZ,cAAc;ArCi2LhB;;AqC/1LA;EpCnCI,oBoCoCoC;ArCk2LxC;;AqCn2LA;EAII,qBtCrM8B;EsCsM9B,oBAAoB;EpChCpB,coCiC6B;ArCm2LjC;;AqCj2LA;EACE,mBAAmB;EACnB,sBAAsB;EACtB,mBAAmB;ArCo2LrB;;AqCv2LA;EAKI,oBAAoB;EACpB,qBAAqB;ArCs2LzB;;AqCp2LA;EACE,4BtC3N4B;EsC4N5B,YAAY;EACZ,aAAa;EACb,WA/LyB;EAgMzB,gBAAgB;ArCu2LlB;;ACr/LE;EoCpCF;IAsLI,cAAc;ErCw2LhB;EqCv2LA;;IAGI,mBAAmB;IACnB,aAAa;ErCw2LjB;EqCv2LA;IAEI,aAAa;ErCw2LjB;EqCh8LF;IA0FI,uBtC3O2B;IsC4O3B,4CtCzPyB;IsC0PzB,iBAAiB;ErCy2LnB;EqC52LA;IAKI,cAAc;ErC02LlB;EqCx2LA;IA3MA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErCqmMjB;EqC92LA;IAKI,SAAS;ErC42Lb;EqCj3LA;IAOM,4CtCrQqB;ECknM3B;EqCp3LA;IASI,MAAM;ErC82LV;EqCv3LA;IpC7LA,iCAAiC;IoC2M3B,iCAA2C;IAC3C,cAAc;ErC62LpB;EqC52LA;;IAGI,oBA9QiB;ErC2nMrB;EqCh3LA;;IAKI,uBAhRiB;ErC+nMrB;AACF;;AC3iME;EoC8LA;;;;IAIE,oBAAoB;IACpB,aAAa;ErCi3Lf;EqCplMF;IAqOI,mBA1RmB;ErC4oMrB;EqCn3LA;IAGI,kBA1R0B;ErC6oM9B;EqCt3LA;;IAMM,mBAAmB;ErCo3LzB;EqC13LA;;IASM,kBtCjOI;ECslMV;EqC93LA;;;;IAgBQ,wCAAwC;ErCo3LhD;EqCp4LA;IAuBU,wCAAwC;ErCg3LlD;EqCv4LA;IA4BU,4BtC7SkB;IsC8SlB,ctCzTiB;ECuqM3B;EqC34LA;IA+BU,4BtChTkB;IsCiTlB,ctCxSsB;ECupMhC;EqCnhMF;IAsKI,aAAa;ErCg3Lf;EqC7gMF;;IAgKI,mBAAmB;IACnB,aAAa;ErCi3Lf;EqC5/LF;IA8IM,oBAAoB;ErCi3LxB;EqCn3LA;IAKM,oDAAoD;ErCi3L1D;EqCt3LA;IAOM,gCtClUsB;IsCmUtB,0BAAkE;IAClE,gBAAgB;IAChB,YAAY;IACZ,4CtC9UqB;IsC+UrB,SAAS;ErCk3Lf;EqC93LA;IAkBM,cAAc;ErC+2LpB;EqC92LM;IAEE,UAAU;IACV,oBAAoB;IACpB,wBAAwB;ErC+2LhC;EqC3iMF;IA8LI,YAAY;IACZ,cAAc;ErCg3LhB;EqC/2LA;IACE,2BAA2B;IpC7K3B,kBoC8KoC;ErCi3LtC;EqCh3LA;IACE,yBAAyB;IpChLzB,iBoCiLoC;ErCk3LtC;EqCx/LF;IAwII,uBtCxV2B;IsCyV3B,8BtCjSc;IsCkSd,+BtClSc;IsCmSd,6BtChW0B;IsCiW1B,2CtCzWyB;IsC0WzB,aAAa;IACb,mBAAmB;IpCjLnB,OoCkLuB;IACvB,eAAe;IACf,kBAAkB;IAClB,SAAS;IACT,WAjVkB;ErCosMpB;EqCtgMF;IAqJM,sBAAsB;IACtB,mBAAmB;ErCo3LvB;EqCn4LA;IpClLE,mBoCmMuC;ErCq3LzC;EqCt4LA;IAoBM,4BtC7WsB;IsC8WtB,ctCzXqB;EC8uM3B;EqC14LA;IAuBM,4BtChXsB;IsCiXtB,ctCxW0B;EC8tMhC;EqCr3LE;IAEE,kBtC1TY;IsC2TZ,gBAAgB;IAChB,4EtCjYuB;IsCkYvB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,wBAA8C;IAC9C,2BAA2B;IAC3B,yBtChUM;IsCiUN,uCAAuC;ErCs3L3C;EqC15LA;IAsCI,UAAU;IACV,QAAQ;ErCu3LZ;EqC7hMF;IAwKI,cAAc;ErCw3LhB;EqCv3LA;;IpC5NE,qBoC+NyC;ErCw3L3C;EqC33LA;;IpC5NE,sBoCiOyC;ErC03L3C;EqCx3LA;IAlWA,OAAO;IACP,eAAe;IACf,QAAQ;IACR,WA/CiB;ErC4wMjB;EqC93LA;IAKI,SAAS;ErC43Lb;EqCj4LA;IAOM,4CtC5ZqB;ECyxM3B;EqCp4LA;IASI,MAAM;ErC83LV;EqC73LA;;IAGI,oBA/ZiB;ErC6xMrB;EqCj4LA;;IAKI,uBAjaiB;ErCiyMrB;EqCr4LA;;IAOI,oBAA4D;ErCk4LhE;EqCz4LA;;IASI,uBAA+D;ErCo4LnE;EqCl4LA;;IAGI,ctC7auB;ECgzM3B;EqCt4LA;;IAKI,6BAla2C;ErCuyM/C;EqCp4LA;IAKM,yBtCzasB;EC2yM5B;AACF;;AqC/3LA;EAEI,iCAA2C;ArCi4L/C;;AsCzxMA;EAEE,evCFW;EuCGX,gBAnC0B;AtC8zM5B;;AsC9xMA;EAMI,kBvCLY;ACiyMhB;;AsClyMA;EAQI,kBvCTY;ACuyMhB;;AsCtyMA;EAUI,iBvCZW;AC4yMf;;AsC1yMA;;EAcM,iBAAiB;EACjB,kBAAkB;EAClB,qBvCmBiB;AC8wMvB;;AsCjzMA;EAkBM,qBvCiBiB;ACkxMvB;;AsCjyMA;;EAEE,mBAAmB;EACnB,aAAa;EACb,uBAAuB;EACvB,kBAAkB;AtCoyMpB;;AsClyMA;;;;EAME,cA9D6B;EA+D7B,uBAAuB;EACvB,eA/D8B;EAgE9B,mBA/DkC;EAgElC,oBA/DmC;EAgEnC,kBAAkB;AtCmyMpB;;AsCjyMA;;;EAGE,qBvCtE4B;EuCuE5B,cvC3E4B;EuC4E5B,gBxC3EoB;AE+2MtB;;AsCzyMA;;;EAOI,qBvC3E0B;EuC4E1B,cvC/E0B;ACu3M9B;;AsChzMA;;;EAUI,qBvCjE8B;AC62MlC;;AsCtzMA;;;EAYI,iDvCvFyB;ACu4M7B;;AsC5zMA;;;;;EAeI,yBvClF0B;EuCmF1B,qBvCnF0B;EuCoF1B,gBAAgB;EAChB,cvCvF0B;EuCwF1B,YAAY;AtCqzMhB;;AsCnzMA;;EAEE,oBAvFkC;EAwFlC,qBAvFmC;EAwFnC,mBAAmB;AtCszMrB;;AsCpzMA;EAEI,yBvCpF8B;EuCqF9B,qBvCrF8B;EuCsF9B,W5B1BY;AVg1MhB;;AsCpzMA;EACE,cvCtG4B;EuCuG5B,oBAAoB;AtCuzMtB;;AsCrzMA;EACE,eAAe;AtCwzMjB;;AsCzzMA;EAGI,gBAAgB;AtC0zMpB;;ACz0ME;EqCjEF;IAoFI,eAAe;EtC2zMjB;EsCl1MF;;IA0BI,YAAY;IACZ,cAAc;EtC4zMhB;EsCv0MF;IAcM,YAAY;IACZ,cAAc;EtC4zMlB;AACF;;ACp1ME;EqCQF;IAmBI,YAAY;IACZ,cAAc;IACd,2BAA2B;IAC3B,QAAQ;EtC8zMV;EsCt4MF;;;;IA6EI,gBAAgB;IAChB,aAAa;EtC+zMf;EsC9zMA;IACE,QAAQ;EtCg0MV;EsC/zMA;IACE,QAAQ;EtCi0MV;EsC96MF;IA+GI,8BAA8B;IAC9B,gBAAgB;IAChB,aAAa;EtCk0Mf;EsCr0MA;IAMM,QAAQ;EtCk0Md;EsCx0MA;IAQM,uBAAuB;IACvB,QAAQ;EtCm0Md;EsC50MA;IAWM,QAAQ;EtCo0Md;EsC/0MA;IAcM,QAAQ;EtCo0Md;EsCl1MA;IAgBM,QAAQ;EtCq0Md;EsCr1MA;IAkBM,yBAAyB;IACzB,QAAQ;EtCs0Md;AACF;;AuC78MA;EACE,kBxCsCgB;EwCrChB,0FxChC2B;EwCiC3B,exCEW;AC88Mb;;AuCn9MA;EAKI,qBxCWkB;ACu8MtB;;AuCv9MA;EAYQ,uBxC7BuB;EwC8BvB,cxC3CqB;AC0/M7B;;AuC59MA;EAeQ,0BxChCuB;ACi/M/B;;AuCh+MA;EAiBQ,YxClCuB;ACq/M/B;;AuCp+MA;EAYQ,yBxC1CqB;EwC2CrB,YxC9BuB;AC0/M/B;;AuCz+MA;EAeQ,4BxC7CqB;AC2gN7B;;AuC7+MA;EAiBQ,cxC/CqB;AC+gN7B;;AuCj/MA;EAYQ,4BxC/BsB;EwCgCtB,yB7BmCa;AVs8MrB;;AuCt/MA;EAeQ,+BxClCsB;AC6gN9B;;AuC1/MA;EAiBQ,iBxCpCsB;ACihN9B;;AuC9/MA;EAYQ,yBxCtCsB;EwCuCtB,W7BqCQ;AVi9MhB;;AuCngNA;EAeQ,4BxCzCsB;ACiiN9B;;AuCvgNA;EAiBQ,cxC3CsB;ACqiN9B;;AuC3gNA;EAYQ,yBxCxB0B;EwCyB1B,W7BqCQ;AV89MhB;;AuChhNA;EAeQ,4BxC3B0B;ACgiNlC;;AuCphNA;EAiBQ,cxC7B0B;ACoiNlC;;AuCxhNA;EAYQ,yBxCtB0B;EwCuB1B,W7BqCQ;AV2+MhB;;AuC7hNA;EAeQ,4BxCzB0B;AC2iNlC;;AuCjiNA;EAiBQ,cxC3B0B;AC+iNlC;;AuCriNA;EAYQ,yBxCvB0B;EwCwB1B,W7BqCQ;AVw/MhB;;AuC1iNA;EAeQ,4BxC1B0B;ACyjNlC;;AuC9iNA;EAiBQ,cxC5B0B;AC6jNlC;;AuCljNA;EAYQ,yBxCzB0B;EwC0B1B,W7BqCQ;AVqgNhB;;AuCvjNA;EAeQ,4BxC5B0B;ACwkNlC;;AuC3jNA;EAiBQ,cxC9B0B;AC4kNlC;;AuC/jNA;EAYQ,yBxC1B0B;EwC2B1B,yB7BmCa;AVohNrB;;AuCpkNA;EAeQ,4BxC7B0B;ACslNlC;;AuCxkNA;EAiBQ,cxC/B0B;AC0lNlC;;AuC5kNA;EAYQ,yBxCpByB;EwCqBzB,W7BqCQ;AV+hNhB;;AuCjlNA;EAeQ,4BxCvByB;AC6lNjC;;AuCrlNA;EAiBQ,cxCzByB;ACimNjC;;AuCtkNA;;EAGI,gCxC3C2B;ACmnN/B;;AuCtkNA;EACE,yBxC9C6B;EwC+C7B,0BAA8C;EAC9C,cxCrD4B;EwCsD5B,iBAhDyB;EAiDzB,gBxCjBe;EwCkBf,iBArD8B;EAsD9B,mBArDgC;AvC8nNlC;;AuCvkNA;EACE,qBAAqB;EACrB,aAAa;EACb,kBArD4B;EAsD5B,uBAAuB;AvC0kNzB;;AuC9kNA;EAMI,gCxC7D0B;EwC8D1B,mBAAmB;EACnB,cAAc;AvC4kNlB;;AuCplNA;EAWM,4BxCrEwB;EwCsExB,cxCvEwB;ACopN9B;;AuC3kNA;EAEI,cxC1E0B;ACupN9B;;AuC/kNA;EAIM,cxC7D4B;AC4oNlC;;AuC7kNA;EACE,mBAAmB;EACnB,cxCjF4B;EwCkF5B,aAAa;EACb,2BAA2B;EAC3B,qBAAqB;AvCglNvB;;AuCrlNA;EtC+FI,oBsCxFsC;AvCklN1C;;AuCzlNA;EASI,YAAY;EACZ,cAAc;EACd,WAAW;AvColNf;;AuC/lNA;EAaI,eAAe;AvCslNnB;;AuCnmNA;EAeI,0BxC9E8B;EwC+E9B,cxC/F0B;ACurN9B;;AuCxmNA;EAkBM,cxCjF4B;AC2qNlC;;AuC5mNA;EAoBI,8BxClCc;EwCmCd,+BxCnCc;AC+nNlB;;AuC1lNA;;EAEE,eAAe;AvC6lNjB;;AuC/lNA;;EAII,4BxCnG0B;ACmsN9B;;AuC9lNA;EtChGE,qBAAqB;EACrB,esCgGgB;EtC/FhB,WsC+FqB;EtC9FrB,gBsC8FqB;EtC7FrB,kBAAkB;EAClB,mBAAmB;EACnB,UsC2FqB;EACrB,cxC5G4B;EE4K1B,oBsC/DoC;AvCumNxC;;AuC1mNA;EAKI,kBAAkB;EAClB,oBAAoB;AvCymNxB;;AwCnsNA;EvCqCE,iCAAiC;EuCjCjC,oBAAoB;EACpB,aAAa;EACb,ezCCW;EyCAX,8BAA8B;EAC9B,gBAAgB;EAChB,gBAAgB;EAChB,mBAAmB;AxCosNrB;;AwC9sNA;EAYI,mBAAmB;EACnB,4BzCjC0B;EyCkC1B,0BAzC4B;EA0C5B,wBAzC0B;EA0C1B,czCvC0B;EyCwC1B,aAAa;EACb,uBAAuB;EACvB,mBAA6C;EAC7C,kBAxCyB;EAyCzB,mBAAmB;AxCssNvB;;AwC3tNA;EAuBM,4BzC/CwB;EyCgDxB,czChDwB;ACwvN9B;;AwChuNA;EA0BI,cAAc;AxC0sNlB;;AwCpuNA;EA6BQ,4BzCrC0B;EyCsC1B,czCtC0B;ACivNlC;;AwCzuNA;EAgCI,mBAAmB;EACnB,4BzCrD0B;EyCsD1B,0BA7D4B;EA8D5B,wBA7D0B;EA8D1B,aAAa;EACb,YAAY;EACZ,cAAc;EACd,2BAA2B;AxC6sN/B;;AwCpvNA;EAyCM,qBAAqB;AxC+sN3B;;AwCxvNA;EA2CM,UAAU;EACV,uBAAuB;EACvB,oBAAoB;EACpB,qBAAqB;AxCitN3B;;AwC/vNA;EAgDM,yBAAyB;EACzB,oBAAoB;AxCmtN1B;;AwCpwNA;EvCsJI,mBuClGuC;AxCotN3C;;AwCxwNA;EvCsJI,kBuChGuC;AxCstN3C;;AwC5wNA;EA0DM,uBAAuB;AxCstN7B;;AwChxNA;EA6DM,yBAAyB;AxCutN/B;;AwCpxNA;EAiEM,6BAA6B;EAE3B,0BAAkE;AxCstN1E;;AwCzxNA;EAuEQ,4BzCxFsB;EyCyFtB,4BzC5FsB;ACkzN9B;;AwC9xNA;EA4EU,uBzC3FqB;EyC4FrB,qBzCjGoB;EyCkGpB,2CAA2E;AxCstNrF;;AwCpyNA;EAiFM,YAAY;EACZ,cAAc;AxCutNpB;;AwCzyNA;EAqFM,qBzCzGwB;EyC0GxB,mBA/F+B;EAgG/B,iBA/F6B;EAgG7B,gBAAgB;EAChB,kBAAkB;AxCwtNxB;;AwCjzNA;EA2FQ,4BzC5GsB;EyC6GtB,qBzCjHsB;EyCkHtB,UAAU;AxC0tNlB;;AwCvzNA;EvCsJI,iBuCtDuE;AxC2tN3E;;AwC3zNA;EAmGU,2BzC3DE;EyC4DF,8BzC5DE;ACwxNZ;;AwCh0NA;EA0GU,4BzClEE;EyCmEF,+BzCnEE;AC6xNZ;;AwCr0NA;EAiHU,yBzCzHwB;EyC0HxB,qBzC1HwB;EyC2HxB,W9B/DM;E8BgEN,UAAU;AxCwtNpB;;AwC50NA;EAsHM,mBAAmB;AxC0tNzB;;AwCh1NA;EA2HY,iCzCjFW;EyCkFX,8BzClFW;EyCmFX,oBAAoB;AxCytNhC;;AwCt1NA;EAoIY,kCzC1FW;EyC2FX,+BzC3FW;EyC4FX,qBAAqB;AxCstNjC;;AwC51NA;EA6II,kBzCrIY;ACw1NhB;;AwCh2NA;EA+II,kBzCzIY;AC81NhB;;AwCp2NA;EAiJI,iBzC5IW;ACm2Nf;;AyCt4NA,eAAA;ACIA;EACE,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,gBAPkB;A1C64NpB;;A0Cr4NE;EACE,UAAU;EACV,YAAY;A1Cw4NhB;;A0Cv4NE;EACE,UAAU;EACV,WAAW;A1C04Nf;;A0Cz4NE;EACE,UAAU;EACV,UAAU;A1C44Nd;;A0C34NE;EACE,UAAU;EACV,eAAe;A1C84NnB;;A0C74NE;EACE,UAAU;EACV,UAAU;A1Cg5Nd;;A0C/4NE;EACE,UAAU;EACV,eAAe;A1Ck5NnB;;A0Cj5NE;EACE,UAAU;EACV,UAAU;A1Co5Nd;;A0Cn5NE;EACE,UAAU;EACV,UAAU;A1Cs5Nd;;A0Cr5NE;EACE,UAAU;EACV,UAAU;A1Cw5Nd;;A0Cv5NE;EACE,UAAU;EACV,UAAU;A1C05Nd;;A0Cz5NE;EACE,UAAU;EACV,UAAU;A1C45Nd;;A0C35NE;EzCyIE,gByCxImC;A1C85NvC;;A0C75NE;EzCuIE,qByCtIwC;A1Cg6N5C;;A0C/5NE;EzCqIE,gByCpImC;A1Ck6NvC;;A0Cj6NE;EzCmIE,qByClIwC;A1Co6N5C;;A0Cn6NE;EzCiIE,gByChImC;A1Cs6NvC;;A0Cr6NE;EzC+HE,gByC9HmC;A1Cw6NvC;;A0Cv6NE;EzC6HE,gByC5HmC;A1C06NvC;;A0Cz6NE;EzC2HE,gByC1HmC;A1C46NvC;;A0C36NE;EzCyHE,gByCxHmC;A1C86NvC;;A0C56NI;EACE,UAAU;EACV,SAAiC;A1C+6NvC;;A0C96NI;EzCmHA,eyClH4D;A1Ci7NhE;;A0Cr7NI;EACE,UAAU;EACV,eAAiC;A1Cw7NvC;;A0Cv7NI;EzCmHA,qByClH4D;A1C07NhE;;A0C97NI;EACE,UAAU;EACV,gBAAiC;A1Ci8NvC;;A0Ch8NI;EzCmHA,sByClH4D;A1Cm8NhE;;A0Cv8NI;EACE,UAAU;EACV,UAAiC;A1C08NvC;;A0Cz8NI;EzCmHA,gByClH4D;A1C48NhE;;A0Ch9NI;EACE,UAAU;EACV,gBAAiC;A1Cm9NvC;;A0Cl9NI;EzCmHA,sByClH4D;A1Cq9NhE;;A0Cz9NI;EACE,UAAU;EACV,gBAAiC;A1C49NvC;;A0C39NI;EzCmHA,sByClH4D;A1C89NhE;;A0Cl+NI;EACE,UAAU;EACV,UAAiC;A1Cq+NvC;;A0Cp+NI;EzCmHA,gByClH4D;A1Cu+NhE;;A0C3+NI;EACE,UAAU;EACV,gBAAiC;A1C8+NvC;;A0C7+NI;EzCmHA,sByClH4D;A1Cg/NhE;;A0Cp/NI;EACE,UAAU;EACV,gBAAiC;A1Cu/NvC;;A0Ct/NI;EzCmHA,sByClH4D;A1Cy/NhE;;A0C7/NI;EACE,UAAU;EACV,UAAiC;A1CggOvC;;A0C//NI;EzCmHA,gByClH4D;A1CkgOhE;;A0CtgOI;EACE,UAAU;EACV,gBAAiC;A1CygOvC;;A0CxgOI;EzCmHA,sByClH4D;A1C2gOhE;;A0C/gOI;EACE,UAAU;EACV,gBAAiC;A1CkhOvC;;A0CjhOI;EzCmHA,sByClH4D;A1CohOhE;;A0CxhOI;EACE,UAAU;EACV,WAAiC;A1C2hOvC;;A0C1hOI;EzCmHA,iByClH4D;A1C6hOhE;;ACz/NE;EyClGF;IAiEM,UAAU;IACV,YAAY;E1C+hOhB;E0CjmOF;IAoEM,UAAU;IACV,WAAW;E1CgiOf;E0CrmOF;IAuEM,UAAU;IACV,UAAU;E1CiiOd;E0CzmOF;IA0EM,UAAU;IACV,eAAe;E1CkiOnB;E0C7mOF;IA6EM,UAAU;IACV,UAAU;E1CmiOd;E0CjnOF;IAgFM,UAAU;IACV,eAAe;E1CoiOnB;E0CrnOF;IAmFM,UAAU;IACV,UAAU;E1CqiOd;E0CznOF;IAsFM,UAAU;IACV,UAAU;E1CsiOd;E0C7nOF;IAyFM,UAAU;IACV,UAAU;E1CuiOd;E0CjoOF;IA4FM,UAAU;IACV,UAAU;E1CwiOd;E0CroOF;IA+FM,UAAU;IACV,UAAU;E1CyiOd;E0CzoOF;IzCgLI,gByC9EqC;E1C0iOvC;E0C5oOF;IzCgLI,qByC5E0C;E1C2iO5C;E0C/oOF;IzCgLI,gByC1EqC;E1C4iOvC;E0ClpOF;IzCgLI,qByCxE0C;E1C6iO5C;E0CrpOF;IzCgLI,gByCtEqC;E1C8iOvC;E0CxpOF;IzCgLI,gByCpEqC;E1C+iOvC;E0C3pOF;IzCgLI,gByClEqC;E1CgjOvC;E0C9pOF;IzCgLI,gByChEqC;E1CijOvC;E0CjqOF;IzCgLI,gByC9DqC;E1CkjOvC;E0CpqOF;IAqHQ,UAAU;IACV,SAAiC;E1CkjOvC;E0CxqOF;IzCgLI,eyCxD8D;E1CmjOhE;E0C3qOF;IAqHQ,UAAU;IACV,eAAiC;E1CyjOvC;E0C/qOF;IzCgLI,qByCxD8D;E1C0jOhE;E0ClrOF;IAqHQ,UAAU;IACV,gBAAiC;E1CgkOvC;E0CtrOF;IzCgLI,sByCxD8D;E1CikOhE;E0CzrOF;IAqHQ,UAAU;IACV,UAAiC;E1CukOvC;E0C7rOF;IzCgLI,gByCxD8D;E1CwkOhE;E0ChsOF;IAqHQ,UAAU;IACV,gBAAiC;E1C8kOvC;E0CpsOF;IzCgLI,sByCxD8D;E1C+kOhE;E0CvsOF;IAqHQ,UAAU;IACV,gBAAiC;E1CqlOvC;E0C3sOF;IzCgLI,sByCxD8D;E1CslOhE;E0C9sOF;IAqHQ,UAAU;IACV,UAAiC;E1C4lOvC;E0CltOF;IzCgLI,gByCxD8D;E1C6lOhE;E0CrtOF;IAqHQ,UAAU;IACV,gBAAiC;E1CmmOvC;E0CztOF;IzCgLI,sByCxD8D;E1ComOhE;E0C5tOF;IAqHQ,UAAU;IACV,gBAAiC;E1C0mOvC;E0ChuOF;IzCgLI,sByCxD8D;E1C2mOhE;E0CnuOF;IAqHQ,UAAU;IACV,UAAiC;E1CinOvC;E0CvuOF;IzCgLI,gByCxD8D;E1CknOhE;E0C1uOF;IAqHQ,UAAU;IACV,gBAAiC;E1CwnOvC;E0C9uOF;IzCgLI,sByCxD8D;E1CynOhE;E0CjvOF;IAqHQ,UAAU;IACV,gBAAiC;E1C+nOvC;E0CrvOF;IzCgLI,sByCxD8D;E1CgoOhE;E0CxvOF;IAqHQ,UAAU;IACV,WAAiC;E1CsoOvC;E0C5vOF;IzCgLI,iByCxD8D;E1CuoOhE;AACF;;AC1pOE;EyCtGF;IA4HM,UAAU;IACV,YAAY;E1CyoOhB;E0CtwOF;IAgIM,UAAU;IACV,WAAW;E1CyoOf;E0C1wOF;IAoIM,UAAU;IACV,UAAU;E1CyoOd;E0C9wOF;IAwIM,UAAU;IACV,eAAe;E1CyoOnB;E0ClxOF;IA4IM,UAAU;IACV,UAAU;E1CyoOd;E0CtxOF;IAgJM,UAAU;IACV,eAAe;E1CyoOnB;E0C1xOF;IAoJM,UAAU;IACV,UAAU;E1CyoOd;E0C9xOF;IAwJM,UAAU;IACV,UAAU;E1CyoOd;E0ClyOF;IA4JM,UAAU;IACV,UAAU;E1CyoOd;E0CtyOF;IAgKM,UAAU;IACV,UAAU;E1CyoOd;E0C1yOF;IAoKM,UAAU;IACV,UAAU;E1CyoOd;E0C9yOF;IzCgLI,gByCRqC;E1CyoOvC;E0CjzOF;IzCgLI,qByCL0C;E1CyoO5C;E0CpzOF;IzCgLI,gByCFqC;E1CyoOvC;E0CvzOF;IzCgLI,qByCC0C;E1CyoO5C;E0C1zOF;IzCgLI,gByCIqC;E1CyoOvC;E0C7zOF;IzCgLI,gByCOqC;E1CyoOvC;E0Ch0OF;IzCgLI,gByCUqC;E1CyoOvC;E0Cn0OF;IzCgLI,gByCaqC;E1CyoOvC;E0Ct0OF;IzCgLI,gByCgBqC;E1CyoOvC;E0Cz0OF;IAoMQ,UAAU;IACV,SAAiC;E1CwoOvC;E0C70OF;IzCgLI,eyCwB8D;E1CwoOhE;E0Ch1OF;IAoMQ,UAAU;IACV,eAAiC;E1C+oOvC;E0Cp1OF;IzCgLI,qByCwB8D;E1C+oOhE;E0Cv1OF;IAoMQ,UAAU;IACV,gBAAiC;E1CspOvC;E0C31OF;IzCgLI,sByCwB8D;E1CspOhE;E0C91OF;IAoMQ,UAAU;IACV,UAAiC;E1C6pOvC;E0Cl2OF;IzCgLI,gByCwB8D;E1C6pOhE;E0Cr2OF;IAoMQ,UAAU;IACV,gBAAiC;E1CoqOvC;E0Cz2OF;IzCgLI,sByCwB8D;E1CoqOhE;E0C52OF;IAoMQ,UAAU;IACV,gBAAiC;E1C2qOvC;E0Ch3OF;IzCgLI,sByCwB8D;E1C2qOhE;E0Cn3OF;IAoMQ,UAAU;IACV,UAAiC;E1CkrOvC;E0Cv3OF;IzCgLI,gByCwB8D;E1CkrOhE;E0C13OF;IAoMQ,UAAU;IACV,gBAAiC;E1CyrOvC;E0C93OF;IzCgLI,sByCwB8D;E1CyrOhE;E0Cj4OF;IAoMQ,UAAU;IACV,gBAAiC;E1CgsOvC;E0Cr4OF;IzCgLI,sByCwB8D;E1CgsOhE;E0Cx4OF;IAoMQ,UAAU;IACV,UAAiC;E1CusOvC;E0C54OF;IzCgLI,gByCwB8D;E1CusOhE;E0C/4OF;IAoMQ,UAAU;IACV,gBAAiC;E1C8sOvC;E0Cn5OF;IzCgLI,sByCwB8D;E1C8sOhE;E0Ct5OF;IAoMQ,UAAU;IACV,gBAAiC;E1CqtOvC;E0C15OF;IzCgLI,sByCwB8D;E1CqtOhE;E0C75OF;IAoMQ,UAAU;IACV,WAAiC;E1C4tOvC;E0Cj6OF;IzCgLI,iByCwB8D;E1C4tOhE;AACF;;ACvzOE;EyC9GF;IA2MM,UAAU;IACV,YAAY;E1C+tOhB;E0C36OF;IA8MM,UAAU;IACV,WAAW;E1CguOf;E0C/6OF;IAiNM,UAAU;IACV,UAAU;E1CiuOd;E0Cn7OF;IAoNM,UAAU;IACV,eAAe;E1CkuOnB;E0Cv7OF;IAuNM,UAAU;IACV,UAAU;E1CmuOd;E0C37OF;IA0NM,UAAU;IACV,eAAe;E1CouOnB;E0C/7OF;IA6NM,UAAU;IACV,UAAU;E1CquOd;E0Cn8OF;IAgOM,UAAU;IACV,UAAU;E1CsuOd;E0Cv8OF;IAmOM,UAAU;IACV,UAAU;E1CuuOd;E0C38OF;IAsOM,UAAU;IACV,UAAU;E1CwuOd;E0C/8OF;IAyOM,UAAU;IACV,UAAU;E1CyuOd;E0Cn9OF;IzCgLI,gByC4DqC;E1C0uOvC;E0Ct9OF;IzCgLI,qByC8D0C;E1C2uO5C;E0Cz9OF;IzCgLI,gByCgEqC;E1C4uOvC;E0C59OF;IzCgLI,qByCkE0C;E1C6uO5C;E0C/9OF;IzCgLI,gByCoEqC;E1C8uOvC;E0Cl+OF;IzCgLI,gByCsEqC;E1C+uOvC;E0Cr+OF;IzCgLI,gByCwEqC;E1CgvOvC;E0Cx+OF;IzCgLI,gByC0EqC;E1CivOvC;E0C3+OF;IzCgLI,gByC4EqC;E1CkvOvC;E0C9+OF;IA+PQ,UAAU;IACV,SAAiC;E1CkvOvC;E0Cl/OF;IzCgLI,eyCkF8D;E1CmvOhE;E0Cr/OF;IA+PQ,UAAU;IACV,eAAiC;E1CyvOvC;E0Cz/OF;IzCgLI,qByCkF8D;E1C0vOhE;E0C5/OF;IA+PQ,UAAU;IACV,gBAAiC;E1CgwOvC;E0ChgPF;IzCgLI,sByCkF8D;E1CiwOhE;E0CngPF;IA+PQ,UAAU;IACV,UAAiC;E1CuwOvC;E0CvgPF;IzCgLI,gByCkF8D;E1CwwOhE;E0C1gPF;IA+PQ,UAAU;IACV,gBAAiC;E1C8wOvC;E0C9gPF;IzCgLI,sByCkF8D;E1C+wOhE;E0CjhPF;IA+PQ,UAAU;IACV,gBAAiC;E1CqxOvC;E0CrhPF;IzCgLI,sByCkF8D;E1CsxOhE;E0CxhPF;IA+PQ,UAAU;IACV,UAAiC;E1C4xOvC;E0C5hPF;IzCgLI,gByCkF8D;E1C6xOhE;E0C/hPF;IA+PQ,UAAU;IACV,gBAAiC;E1CmyOvC;E0CniPF;IzCgLI,sByCkF8D;E1CoyOhE;E0CtiPF;IA+PQ,UAAU;IACV,gBAAiC;E1C0yOvC;E0C1iPF;IzCgLI,sByCkF8D;E1C2yOhE;E0C7iPF;IA+PQ,UAAU;IACV,UAAiC;E1CizOvC;E0CjjPF;IzCgLI,gByCkF8D;E1CkzOhE;E0CpjPF;IA+PQ,UAAU;IACV,gBAAiC;E1CwzOvC;E0CxjPF;IzCgLI,sByCkF8D;E1CyzOhE;E0C3jPF;IA+PQ,UAAU;IACV,gBAAiC;E1C+zOvC;E0C/jPF;IzCgLI,sByCkF8D;E1Cg0OhE;E0ClkPF;IA+PQ,UAAU;IACV,WAAiC;E1Cs0OvC;E0CtkPF;IzCgLI,iByCkF8D;E1Cu0OhE;AACF;;ACx9OE;EyClHF;IAqQM,UAAU;IACV,YAAY;E1C00OhB;E0ChlPF;IAwQM,UAAU;IACV,WAAW;E1C20Of;E0CplPF;IA2QM,UAAU;IACV,UAAU;E1C40Od;E0CxlPF;IA8QM,UAAU;IACV,eAAe;E1C60OnB;E0C5lPF;IAiRM,UAAU;IACV,UAAU;E1C80Od;E0ChmPF;IAoRM,UAAU;IACV,eAAe;E1C+0OnB;E0CpmPF;IAuRM,UAAU;IACV,UAAU;E1Cg1Od;E0CxmPF;IA0RM,UAAU;IACV,UAAU;E1Ci1Od;E0C5mPF;IA6RM,UAAU;IACV,UAAU;E1Ck1Od;E0ChnPF;IAgSM,UAAU;IACV,UAAU;E1Cm1Od;E0CpnPF;IAmSM,UAAU;IACV,UAAU;E1Co1Od;E0CxnPF;IzCgLI,gByCsHqC;E1Cq1OvC;E0C3nPF;IzCgLI,qByCwH0C;E1Cs1O5C;E0C9nPF;IzCgLI,gByC0HqC;E1Cu1OvC;E0CjoPF;IzCgLI,qByC4H0C;E1Cw1O5C;E0CpoPF;IzCgLI,gByC8HqC;E1Cy1OvC;E0CvoPF;IzCgLI,gByCgIqC;E1C01OvC;E0C1oPF;IzCgLI,gByCkIqC;E1C21OvC;E0C7oPF;IzCgLI,gByCoIqC;E1C41OvC;E0ChpPF;IzCgLI,gByCsIqC;E1C61OvC;E0CnpPF;IAyTQ,UAAU;IACV,SAAiC;E1C61OvC;E0CvpPF;IzCgLI,eyC4I8D;E1C81OhE;E0C1pPF;IAyTQ,UAAU;IACV,eAAiC;E1Co2OvC;E0C9pPF;IzCgLI,qByC4I8D;E1Cq2OhE;E0CjqPF;IAyTQ,UAAU;IACV,gBAAiC;E1C22OvC;E0CrqPF;IzCgLI,sByC4I8D;E1C42OhE;E0CxqPF;IAyTQ,UAAU;IACV,UAAiC;E1Ck3OvC;E0C5qPF;IzCgLI,gByC4I8D;E1Cm3OhE;E0C/qPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cy3OvC;E0CnrPF;IzCgLI,sByC4I8D;E1C03OhE;E0CtrPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cg4OvC;E0C1rPF;IzCgLI,sByC4I8D;E1Ci4OhE;E0C7rPF;IAyTQ,UAAU;IACV,UAAiC;E1Cu4OvC;E0CjsPF;IzCgLI,gByC4I8D;E1Cw4OhE;E0CpsPF;IAyTQ,UAAU;IACV,gBAAiC;E1C84OvC;E0CxsPF;IzCgLI,sByC4I8D;E1C+4OhE;E0C3sPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cq5OvC;E0C/sPF;IzCgLI,sByC4I8D;E1Cs5OhE;E0CltPF;IAyTQ,UAAU;IACV,UAAiC;E1C45OvC;E0CttPF;IzCgLI,gByC4I8D;E1C65OhE;E0CztPF;IAyTQ,UAAU;IACV,gBAAiC;E1Cm6OvC;E0C7tPF;IzCgLI,sByC4I8D;E1Co6OhE;E0ChuPF;IAyTQ,UAAU;IACV,gBAAiC;E1C06OvC;E0CpuPF;IzCgLI,sByC4I8D;E1C26OhE;E0CvuPF;IAyTQ,UAAU;IACV,WAAiC;E1Ci7OvC;E0C3uPF;IzCgLI,iByC4I8D;E1Ck7OhE;AACF;;AC9mPI;EyCjIJ;IA+TM,UAAU;IACV,YAAY;E1Cq7OhB;E0CrvPF;IAkUM,UAAU;IACV,WAAW;E1Cs7Of;E0CzvPF;IAqUM,UAAU;IACV,UAAU;E1Cu7Od;E0C7vPF;IAwUM,UAAU;IACV,eAAe;E1Cw7OnB;E0CjwPF;IA2UM,UAAU;IACV,UAAU;E1Cy7Od;E0CrwPF;IA8UM,UAAU;IACV,eAAe;E1C07OnB;E0CzwPF;IAiVM,UAAU;IACV,UAAU;E1C27Od;E0C7wPF;IAoVM,UAAU;IACV,UAAU;E1C47Od;E0CjxPF;IAuVM,UAAU;IACV,UAAU;E1C67Od;E0CrxPF;IA0VM,UAAU;IACV,UAAU;E1C87Od;E0CzxPF;IA6VM,UAAU;IACV,UAAU;E1C+7Od;E0C7xPF;IzCgLI,gByCgLqC;E1Cg8OvC;E0ChyPF;IzCgLI,qByCkL0C;E1Ci8O5C;E0CnyPF;IzCgLI,gByCoLqC;E1Ck8OvC;E0CtyPF;IzCgLI,qByCsL0C;E1Cm8O5C;E0CzyPF;IzCgLI,gByCwLqC;E1Co8OvC;E0C5yPF;IzCgLI,gByC0LqC;E1Cq8OvC;E0C/yPF;IzCgLI,gByC4LqC;E1Cs8OvC;E0ClzPF;IzCgLI,gByC8LqC;E1Cu8OvC;E0CrzPF;IzCgLI,gByCgMqC;E1Cw8OvC;E0CxzPF;IAmXQ,UAAU;IACV,SAAiC;E1Cw8OvC;E0C5zPF;IzCgLI,eyCsM8D;E1Cy8OhE;E0C/zPF;IAmXQ,UAAU;IACV,eAAiC;E1C+8OvC;E0Cn0PF;IzCgLI,qByCsM8D;E1Cg9OhE;E0Ct0PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cs9OvC;E0C10PF;IzCgLI,sByCsM8D;E1Cu9OhE;E0C70PF;IAmXQ,UAAU;IACV,UAAiC;E1C69OvC;E0Cj1PF;IzCgLI,gByCsM8D;E1C89OhE;E0Cp1PF;IAmXQ,UAAU;IACV,gBAAiC;E1Co+OvC;E0Cx1PF;IzCgLI,sByCsM8D;E1Cq+OhE;E0C31PF;IAmXQ,UAAU;IACV,gBAAiC;E1C2+OvC;E0C/1PF;IzCgLI,sByCsM8D;E1C4+OhE;E0Cl2PF;IAmXQ,UAAU;IACV,UAAiC;E1Ck/OvC;E0Ct2PF;IzCgLI,gByCsM8D;E1Cm/OhE;E0Cz2PF;IAmXQ,UAAU;IACV,gBAAiC;E1Cy/OvC;E0C72PF;IzCgLI,sByCsM8D;E1C0/OhE;E0Ch3PF;IAmXQ,UAAU;IACV,gBAAiC;E1CggPvC;E0Cp3PF;IzCgLI,sByCsM8D;E1CigPhE;E0Cv3PF;IAmXQ,UAAU;IACV,UAAiC;E1CugPvC;E0C33PF;IzCgLI,gByCsM8D;E1CwgPhE;E0C93PF;IAmXQ,UAAU;IACV,gBAAiC;E1C8gPvC;E0Cl4PF;IzCgLI,sByCsM8D;E1C+gPhE;E0Cr4PF;IAmXQ,UAAU;IACV,gBAAiC;E1CqhPvC;E0Cz4PF;IzCgLI,sByCsM8D;E1CshPhE;E0C54PF;IAmXQ,UAAU;IACV,WAAiC;E1C4hPvC;E0Ch5PF;IzCgLI,iByCsM8D;E1C6hPhE;AACF;;ACpwPI;EyChJJ;IAyXM,UAAU;IACV,YAAY;E1CgiPhB;E0C15PF;IA4XM,UAAU;IACV,WAAW;E1CiiPf;E0C95PF;IA+XM,UAAU;IACV,UAAU;E1CkiPd;E0Cl6PF;IAkYM,UAAU;IACV,eAAe;E1CmiPnB;E0Ct6PF;IAqYM,UAAU;IACV,UAAU;E1CoiPd;E0C16PF;IAwYM,UAAU;IACV,eAAe;E1CqiPnB;E0C96PF;IA2YM,UAAU;IACV,UAAU;E1CsiPd;E0Cl7PF;IA8YM,UAAU;IACV,UAAU;E1CuiPd;E0Ct7PF;IAiZM,UAAU;IACV,UAAU;E1CwiPd;E0C17PF;IAoZM,UAAU;IACV,UAAU;E1CyiPd;E0C97PF;IAuZM,UAAU;IACV,UAAU;E1C0iPd;E0Cl8PF;IzCgLI,gByC0OqC;E1C2iPvC;E0Cr8PF;IzCgLI,qByC4O0C;E1C4iP5C;E0Cx8PF;IzCgLI,gByC8OqC;E1C6iPvC;E0C38PF;IzCgLI,qByCgP0C;E1C8iP5C;E0C98PF;IzCgLI,gByCkPqC;E1C+iPvC;E0Cj9PF;IzCgLI,gByCoPqC;E1CgjPvC;E0Cp9PF;IzCgLI,gByCsPqC;E1CijPvC;E0Cv9PF;IzCgLI,gByCwPqC;E1CkjPvC;E0C19PF;IzCgLI,gByC0PqC;E1CmjPvC;E0C79PF;IA6aQ,UAAU;IACV,SAAiC;E1CmjPvC;E0Cj+PF;IzCgLI,eyCgQ8D;E1CojPhE;E0Cp+PF;IA6aQ,UAAU;IACV,eAAiC;E1C0jPvC;E0Cx+PF;IzCgLI,qByCgQ8D;E1C2jPhE;E0C3+PF;IA6aQ,UAAU;IACV,gBAAiC;E1CikPvC;E0C/+PF;IzCgLI,sByCgQ8D;E1CkkPhE;E0Cl/PF;IA6aQ,UAAU;IACV,UAAiC;E1CwkPvC;E0Ct/PF;IzCgLI,gByCgQ8D;E1CykPhE;E0Cz/PF;IA6aQ,UAAU;IACV,gBAAiC;E1C+kPvC;E0C7/PF;IzCgLI,sByCgQ8D;E1CglPhE;E0ChgQF;IA6aQ,UAAU;IACV,gBAAiC;E1CslPvC;E0CpgQF;IzCgLI,sByCgQ8D;E1CulPhE;E0CvgQF;IA6aQ,UAAU;IACV,UAAiC;E1C6lPvC;E0C3gQF;IzCgLI,gByCgQ8D;E1C8lPhE;E0C9gQF;IA6aQ,UAAU;IACV,gBAAiC;E1ComPvC;E0ClhQF;IzCgLI,sByCgQ8D;E1CqmPhE;E0CrhQF;IA6aQ,UAAU;IACV,gBAAiC;E1C2mPvC;E0CzhQF;IzCgLI,sByCgQ8D;E1C4mPhE;E0C5hQF;IA6aQ,UAAU;IACV,UAAiC;E1CknPvC;E0ChiQF;IzCgLI,gByCgQ8D;E1CmnPhE;E0CniQF;IA6aQ,UAAU;IACV,gBAAiC;E1CynPvC;E0CviQF;IzCgLI,sByCgQ8D;E1C0nPhE;E0C1iQF;IA6aQ,UAAU;IACV,gBAAiC;E1CgoPvC;E0C9iQF;IzCgLI,sByCgQ8D;E1CioPhE;E0CjjQF;IA6aQ,UAAU;IACV,WAAiC;E1CuoPvC;E0CrjQF;IzCgLI,iByCgQ8D;E1CwoPhE;AACF;;A0CvoPA;EzClQI,qByClLgB;EzCkLhB,sByClLgB;EAublB,oBAvbkB;A1CikQpB;;A0C7oPA;EAKI,uBAzbgB;A1CqkQpB;;A0CjpPA;EAOI,qCAA4C;A1C8oPhD;;A0CrpPA;EAUI,uBAAuB;A1C+oP3B;;A0CzpPA;EzClQI,cyC8QiC;EzC9QjC,eyC+QiC;EACjC,aAAa;A1CipPjB;;A0C/pPA;EAgBM,SAAS;EACT,qBAAqB;A1CmpP3B;;A0CpqPA;EAmBM,qBAAqB;A1CqpP3B;;A0CxqPA;EAqBM,gBAAgB;A1CupPtB;;A0C5qPA;EAuBI,aAAa;A1CypPjB;;A0ChrPA;EAyBI,eAAe;A1C2pPnB;;A0CprPA;EA2BI,mBAAmB;A1C6pPvB;;ACpgQE;EyC4UF;IA+BM,aAAa;E1C8pPjB;AACF;;AC9/PE;EyCgUF;IAmCM,aAAa;E1CgqPjB;AACF;;A0C9pPE;EACE,oBAAY;EzCzSZ,wCyC0S2D;EzC1S3D,yCyC2S2D;A1CiqP/D;;A0CpqPE;EAKI,8BAA8B;EAC9B,+BAA+B;A1CmqPrC;;A0CzqPE;EASM,iBAAY;A1CoqPpB;;ACniQE;EyCsXA;IAYQ,iBAAY;E1CsqPpB;AACF;;ACriQE;EyCkXA;IAeQ,iBAAY;E1CyqPpB;AACF;;ACviQE;EyC8WA;IAkBQ,iBAAY;E1C4qPpB;AACF;;ACziQE;EyC0WA;IAqBQ,iBAAY;E1C+qPpB;AACF;;AC3iQE;EyCsWA;IAwBQ,iBAAY;E1CkrPpB;AACF;;AC5iQI;EyCiWF;IA2BQ,iBAAY;E1CqrPpB;AACF;;ACxiQI;EyCuVF;IA8BQ,iBAAY;E1CwrPpB;AACF;;ACziQI;EyCkVF;IAiCQ,iBAAY;E1C2rPpB;AACF;;ACriQI;EyCwUF;IAoCQ,iBAAY;E1C8rPpB;AACF;;A0CnuPE;EASM,oBAAY;A1C8tPpB;;AC7lQE;EyCsXA;IAYQ,oBAAY;E1CguPpB;AACF;;AC/lQE;EyCkXA;IAeQ,oBAAY;E1CmuPpB;AACF;;ACjmQE;EyC8WA;IAkBQ,oBAAY;E1CsuPpB;AACF;;ACnmQE;EyC0WA;IAqBQ,oBAAY;E1CyuPpB;AACF;;ACrmQE;EyCsWA;IAwBQ,oBAAY;E1C4uPpB;AACF;;ACtmQI;EyCiWF;IA2BQ,oBAAY;E1C+uPpB;AACF;;AClmQI;EyCuVF;IA8BQ,oBAAY;E1CkvPpB;AACF;;ACnmQI;EyCkVF;IAiCQ,oBAAY;E1CqvPpB;AACF;;AC/lQI;EyCwUF;IAoCQ,oBAAY;E1CwvPpB;AACF;;A0C7xPE;EASM,mBAAY;A1CwxPpB;;ACvpQE;EyCsXA;IAYQ,mBAAY;E1C0xPpB;AACF;;ACzpQE;EyCkXA;IAeQ,mBAAY;E1C6xPpB;AACF;;AC3pQE;EyC8WA;IAkBQ,mBAAY;E1CgyPpB;AACF;;AC7pQE;EyC0WA;IAqBQ,mBAAY;E1CmyPpB;AACF;;AC/pQE;EyCsWA;IAwBQ,mBAAY;E1CsyPpB;AACF;;AChqQI;EyCiWF;IA2BQ,mBAAY;E1CyyPpB;AACF;;AC5pQI;EyCuVF;IA8BQ,mBAAY;E1C4yPpB;AACF;;AC7pQI;EyCkVF;IAiCQ,mBAAY;E1C+yPpB;AACF;;ACzpQI;EyCwUF;IAoCQ,mBAAY;E1CkzPpB;AACF;;A0Cv1PE;EASM,oBAAY;A1Ck1PpB;;ACjtQE;EyCsXA;IAYQ,oBAAY;E1Co1PpB;AACF;;ACntQE;EyCkXA;IAeQ,oBAAY;E1Cu1PpB;AACF;;ACrtQE;EyC8WA;IAkBQ,oBAAY;E1C01PpB;AACF;;ACvtQE;EyC0WA;IAqBQ,oBAAY;E1C61PpB;AACF;;ACztQE;EyCsWA;IAwBQ,oBAAY;E1Cg2PpB;AACF;;AC1tQI;EyCiWF;IA2BQ,oBAAY;E1Cm2PpB;AACF;;ACttQI;EyCuVF;IA8BQ,oBAAY;E1Cs2PpB;AACF;;ACvtQI;EyCkVF;IAiCQ,oBAAY;E1Cy2PpB;AACF;;ACntQI;EyCwUF;IAoCQ,oBAAY;E1C42PpB;AACF;;A0Cj5PE;EASM,iBAAY;A1C44PpB;;AC3wQE;EyCsXA;IAYQ,iBAAY;E1C84PpB;AACF;;AC7wQE;EyCkXA;IAeQ,iBAAY;E1Ci5PpB;AACF;;AC/wQE;EyC8WA;IAkBQ,iBAAY;E1Co5PpB;AACF;;ACjxQE;EyC0WA;IAqBQ,iBAAY;E1Cu5PpB;AACF;;ACnxQE;EyCsWA;IAwBQ,iBAAY;E1C05PpB;AACF;;ACpxQI;EyCiWF;IA2BQ,iBAAY;E1C65PpB;AACF;;AChxQI;EyCuVF;IA8BQ,iBAAY;E1Cg6PpB;AACF;;ACjxQI;EyCkVF;IAiCQ,iBAAY;E1Cm6PpB;AACF;;AC7wQI;EyCwUF;IAoCQ,iBAAY;E1Cs6PpB;AACF;;A0C38PE;EASM,oBAAY;A1Cs8PpB;;ACr0QE;EyCsXA;IAYQ,oBAAY;E1Cw8PpB;AACF;;ACv0QE;EyCkXA;IAeQ,oBAAY;E1C28PpB;AACF;;ACz0QE;EyC8WA;IAkBQ,oBAAY;E1C88PpB;AACF;;AC30QE;EyC0WA;IAqBQ,oBAAY;E1Ci9PpB;AACF;;AC70QE;EyCsWA;IAwBQ,oBAAY;E1Co9PpB;AACF;;AC90QI;EyCiWF;IA2BQ,oBAAY;E1Cu9PpB;AACF;;AC10QI;EyCuVF;IA8BQ,oBAAY;E1C09PpB;AACF;;AC30QI;EyCkVF;IAiCQ,oBAAY;E1C69PpB;AACF;;ACv0QI;EyCwUF;IAoCQ,oBAAY;E1Cg+PpB;AACF;;A0CrgQE;EASM,mBAAY;A1CggQpB;;AC/3QE;EyCsXA;IAYQ,mBAAY;E1CkgQpB;AACF;;ACj4QE;EyCkXA;IAeQ,mBAAY;E1CqgQpB;AACF;;ACn4QE;EyC8WA;IAkBQ,mBAAY;E1CwgQpB;AACF;;ACr4QE;EyC0WA;IAqBQ,mBAAY;E1C2gQpB;AACF;;ACv4QE;EyCsWA;IAwBQ,mBAAY;E1C8gQpB;AACF;;ACx4QI;EyCiWF;IA2BQ,mBAAY;E1CihQpB;AACF;;ACp4QI;EyCuVF;IA8BQ,mBAAY;E1CohQpB;AACF;;ACr4QI;EyCkVF;IAiCQ,mBAAY;E1CuhQpB;AACF;;ACj4QI;EyCwUF;IAoCQ,mBAAY;E1C0hQpB;AACF;;A0C/jQE;EASM,oBAAY;A1C0jQpB;;ACz7QE;EyCsXA;IAYQ,oBAAY;E1C4jQpB;AACF;;AC37QE;EyCkXA;IAeQ,oBAAY;E1C+jQpB;AACF;;AC77QE;EyC8WA;IAkBQ,oBAAY;E1CkkQpB;AACF;;AC/7QE;EyC0WA;IAqBQ,oBAAY;E1CqkQpB;AACF;;ACj8QE;EyCsWA;IAwBQ,oBAAY;E1CwkQpB;AACF;;ACl8QI;EyCiWF;IA2BQ,oBAAY;E1C2kQpB;AACF;;AC97QI;EyCuVF;IA8BQ,oBAAY;E1C8kQpB;AACF;;AC/7QI;EyCkVF;IAiCQ,oBAAY;E1CilQpB;AACF;;AC37QI;EyCwUF;IAoCQ,oBAAY;E1ColQpB;AACF;;A0CznQE;EASM,iBAAY;A1ConQpB;;ACn/QE;EyCsXA;IAYQ,iBAAY;E1CsnQpB;AACF;;ACr/QE;EyCkXA;IAeQ,iBAAY;E1CynQpB;AACF;;ACv/QE;EyC8WA;IAkBQ,iBAAY;E1C4nQpB;AACF;;ACz/QE;EyC0WA;IAqBQ,iBAAY;E1C+nQpB;AACF;;AC3/QE;EyCsWA;IAwBQ,iBAAY;E1CkoQpB;AACF;;AC5/QI;EyCiWF;IA2BQ,iBAAY;E1CqoQpB;AACF;;ACx/QI;EyCuVF;IA8BQ,iBAAY;E1CwoQpB;AACF;;ACz/QI;EyCkVF;IAiCQ,iBAAY;E1C2oQpB;AACF;;ACr/QI;EyCwUF;IAoCQ,iBAAY;E1C8oQpB;AACF;;A2C3oRA;EACE,oBAAoB;EACpB,cAAc;EACd,aAAa;EACb,YAAY;EACZ,cAAc;EACd,+BAAuB;EAAvB,4BAAuB;EAAvB,uBAAuB;A3C8oRzB;;A2CppRA;EASI,qBAA+B;EAC/B,sBAAgC;EAChC,oBAA8B;A3C+oRlC;;A2C1pRA;EAaM,uBAAiC;A3CipRvC;;A2C9pRA;EAeM,sBAjBgB;A3CoqRtB;;A2ClqRA;EAiBI,oBAAoB;A3CqpRxB;;A2CtqRA;EAmBI,gBArBkB;A3C4qRtB;;A2C1qRA;EAqBI,sBAAsB;A3CypR1B;;A2C9qRA;EAuBM,gCAAgC;A3C2pRtC;;AC5kRE;E0CtGF;IA2BM,aAAa;E3C4pRjB;E2CvrRF;IA8BQ,UAAU;IACV,eAA8B;E3C4pRpC;E2C3rRF;IA8BQ,UAAU;IACV,gBAA8B;E3CgqRpC;E2C/rRF;IA8BQ,UAAU;IACV,UAA8B;E3CoqRpC;E2CnsRF;IA8BQ,UAAU;IACV,gBAA8B;E3CwqRpC;E2CvsRF;IA8BQ,UAAU;IACV,gBAA8B;E3C4qRpC;E2C3sRF;IA8BQ,UAAU;IACV,UAA8B;E3CgrRpC;E2C/sRF;IA8BQ,UAAU;IACV,gBAA8B;E3CorRpC;E2CntRF;IA8BQ,UAAU;IACV,gBAA8B;E3CwrRpC;E2CvtRF;IA8BQ,UAAU;IACV,UAA8B;E3C4rRpC;E2C3tRF;IA8BQ,UAAU;IACV,gBAA8B;E3CgsRpC;E2C/tRF;IA8BQ,UAAU;IACV,gBAA8B;E3CosRpC;E2CnuRF;IA8BQ,UAAU;IACV,WAA8B;E3CwsRpC;AACF;;A4C5uRA,kBAAA;ACIE;EACE,uBAAwB;A7C4uR5B;;A6C3uRE;EAGI,yBAA0C;A7C4uRhD;;A6C3uRE;EACE,kCAAmC;A7C8uRvC;;A6CrvRE;EACE,yBAAwB;A7CwvR5B;;A6CvvRE;EAGI,uBAA0C;A7CwvRhD;;A6CvvRE;EACE,oCAAmC;A7C0vRvC;;A6CjwRE;EACE,4BAAwB;A7CowR5B;;A6CnwRE;EAGI,yBAA0C;A7CowRhD;;A6CnwRE;EACE,uCAAmC;A7CswRvC;;A6C7wRE;EACE,yBAAwB;A7CgxR5B;;A6C/wRE;EAGI,yBAA0C;A7CgxRhD;;A6C/wRE;EACE,oCAAmC;A7CkxRvC;;A6CzxRE;EACE,yBAAwB;A7C4xR5B;;A6C3xRE;EAGI,yBAA0C;A7C4xRhD;;A6C3xRE;EACE,oCAAmC;A7C8xRvC;;A6CzxRI;EACE,yBAA8B;A7C4xRpC;;A6C3xRI;EAGI,yBAAgD;A7C4xRxD;;A6C3xRI;EACE,oCAAyC;A7C8xR/C;;A6C5xRI;EACE,yBAA6B;A7C+xRnC;;A6C9xRI;EAGI,yBAAgD;A7C+xRxD;;A6C9xRI;EACE,oCAAwC;A7CiyR9C;;A6C7zRE;EACE,yBAAwB;A7Cg0R5B;;A6C/zRE;EAGI,yBAA0C;A7Cg0RhD;;A6C/zRE;EACE,oCAAmC;A7Ck0RvC;;A6C7zRI;EACE,yBAA8B;A7Cg0RpC;;A6C/zRI;EAGI,yBAAgD;A7Cg0RxD;;A6C/zRI;EACE,oCAAyC;A7Ck0R/C;;A6Ch0RI;EACE,yBAA6B;A7Cm0RnC;;A6Cl0RI;EAGI,yBAAgD;A7Cm0RxD;;A6Cl0RI;EACE,oCAAwC;A7Cq0R9C;;A6Cj2RE;EACE,yBAAwB;A7Co2R5B;;A6Cn2RE;EAGI,yBAA0C;A7Co2RhD;;A6Cn2RE;EACE,oCAAmC;A7Cs2RvC;;A6Cj2RI;EACE,yBAA8B;A7Co2RpC;;A6Cn2RI;EAGI,yBAAgD;A7Co2RxD;;A6Cn2RI;EACE,oCAAyC;A7Cs2R/C;;A6Cp2RI;EACE,yBAA6B;A7Cu2RnC;;A6Ct2RI;EAGI,yBAAgD;A7Cu2RxD;;A6Ct2RI;EACE,oCAAwC;A7Cy2R9C;;A6Cr4RE;EACE,yBAAwB;A7Cw4R5B;;A6Cv4RE;EAGI,yBAA0C;A7Cw4RhD;;A6Cv4RE;EACE,oCAAmC;A7C04RvC;;A6Cr4RI;EACE,yBAA8B;A7Cw4RpC;;A6Cv4RI;EAGI,yBAAgD;A7Cw4RxD;;A6Cv4RI;EACE,oCAAyC;A7C04R/C;;A6Cx4RI;EACE,yBAA6B;A7C24RnC;;A6C14RI;EAGI,yBAAgD;A7C24RxD;;A6C14RI;EACE,oCAAwC;A7C64R9C;;A6Cz6RE;EACE,yBAAwB;A7C46R5B;;A6C36RE;EAGI,yBAA0C;A7C46RhD;;A6C36RE;EACE,oCAAmC;A7C86RvC;;A6Cz6RI;EACE,yBAA8B;A7C46RpC;;A6C36RI;EAGI,yBAAgD;A7C46RxD;;A6C36RI;EACE,oCAAyC;A7C86R/C;;A6C56RI;EACE,yBAA6B;A7C+6RnC;;A6C96RI;EAGI,yBAAgD;A7C+6RxD;;A6C96RI;EACE,oCAAwC;A7Ci7R9C;;A6C78RE;EACE,yBAAwB;A7Cg9R5B;;A6C/8RE;EAGI,yBAA0C;A7Cg9RhD;;A6C/8RE;EACE,oCAAmC;A7Ck9RvC;;A6C78RI;EACE,yBAA8B;A7Cg9RpC;;A6C/8RI;EAGI,yBAAgD;A7Cg9RxD;;A6C/8RI;EACE,oCAAyC;A7Ck9R/C;;A6Ch9RI;EACE,yBAA6B;A7Cm9RnC;;A6Cl9RI;EAGI,yBAAgD;A7Cm9RxD;;A6Cl9RI;EACE,oCAAwC;A7Cq9R9C;;A6Cl9RE;EACE,yBAAwB;A7Cq9R5B;;A6Cp9RE;EACE,oCAAmC;A7Cu9RvC;;A6C19RE;EACE,yBAAwB;A7C69R5B;;A6C59RE;EACE,oCAAmC;A7C+9RvC;;A6Cl+RE;EACE,yBAAwB;A7Cq+R5B;;A6Cp+RE;EACE,oCAAmC;A7Cu+RvC;;A6C1+RE;EACE,yBAAwB;A7C6+R5B;;A6C5+RE;EACE,oCAAmC;A7C++RvC;;A6Cl/RE;EACE,yBAAwB;A7Cq/R5B;;A6Cp/RE;EACE,oCAAmC;A7Cu/RvC;;A6C1/RE;EACE,yBAAwB;A7C6/R5B;;A6C5/RE;EACE,oCAAmC;A7C+/RvC;;A6ClgSE;EACE,yBAAwB;A7CqgS5B;;A6CpgSE;EACE,oCAAmC;A7CugSvC;;A6C1gSE;EACE,4BAAwB;A7C6gS5B;;A6C5gSE;EACE,uCAAmC;A7C+gSvC;;A6ClhSE;EACE,yBAAwB;A7CqhS5B;;A6CphSE;EACE,oCAAmC;A7CuhSvC;;A8C3jSE;EACE,8BAAiC;A9C8jSrC;;A8C/jSE;EACE,sCAAiC;A9CkkSrC;;A8CnkSE;EACE,iCAAiC;A9CskSrC;;A8CvkSE;EACE,yCAAiC;A9C0kSrC;;A8CtkSE;EACE,4BAA4B;A9CykShC;;A8C1kSE;EACE,0BAA4B;A9C6kShC;;A8C9kSE;EACE,kCAA4B;A9CilShC;;A8C7kSE;EACE,sCAAkC;A9CglStC;;A8CjlSE;EACE,oCAAkC;A9ColStC;;A8CrlSE;EACE,kCAAkC;A9CwlStC;;A8CzlSE;EACE,yCAAkC;A9C4lStC;;A8C7lSE;EACE,wCAAkC;A9CgmStC;;A8CjmSE;EACE,wCAAkC;A9ComStC;;A8CrmSE;EACE,iCAAkC;A9CwmStC;;A8CzmSE;EACE,+BAAkC;A9C4mStC;;A8C7mSE;EACE,gCAAkC;A9CgnStC;;A8CjnSE;EACE,iCAAkC;A9ConStC;;A8ChnSE;EACE,oCAAgC;A9CmnSpC;;A8CpnSE;EACE,kCAAgC;A9CunSpC;;A8CxnSE;EACE,gCAAgC;A9C2nSpC;;A8C5nSE;EACE,uCAAgC;A9C+nSpC;;A8ChoSE;EACE,sCAAgC;A9CmoSpC;;A8CpoSE;EACE,sCAAgC;A9CuoSpC;;A8CxoSE;EACE,iCAAgC;A9C2oSpC;;A8C5oSE;EACE,+BAAgC;A9C+oSpC;;A8ChpSE;EACE,6BAAgC;A9CmpSpC;;A8CppSE;EACE,kCAAgC;A9CupSpC;;A8CnpSE;EACE,+BAA8B;A9CspSlC;;A8CvpSE;EACE,kCAA8B;A9C0pSlC;;A8C3pSE;EACE,gCAA8B;A9C8pSlC;;A8C/pSE;EACE,8BAA8B;A9CkqSlC;;A8CnqSE;EACE,gCAA8B;A9CsqSlC;;A8CvqSE;EACE,6BAA8B;A9C0qSlC;;A8C3qSE;EACE,2BAA8B;A9C8qSlC;;A8C/qSE;EACE,kCAA8B;A9CkrSlC;;A8CnrSE;EACE,gCAA8B;A9CsrSlC;;A8ClrSE;EACE,2BAA6B;A9CqrSjC;;A8CtrSE;EACE,iCAA6B;A9CyrSjC;;A8C1rSE;EACE,+BAA6B;A9C6rSjC;;A8C9rSE;EACE,6BAA6B;A9CisSjC;;A8ClsSE;EACE,+BAA6B;A9CqsSjC;;A8CtsSE;EACE,8BAA6B;A9CysSjC;;A8CpsSI;EACE,uBAAqC;A9CusS3C;;A8CxsSI;EACE,uBAAqC;A9C2sS3C;;A8C5sSI;EACE,uBAAqC;A9C+sS3C;;A8ChtSI;EACE,uBAAqC;A9CmtS3C;;A8CptSI;EACE,uBAAqC;A9CutS3C;;A8CxtSI;EACE,uBAAqC;A9C2tS3C;;A8C5tSI;EACE,yBAAqC;A9C+tS3C;;A8ChuSI;EACE,yBAAqC;A9CmuS3C;;A8CpuSI;EACE,yBAAqC;A9CuuS3C;;A8CxuSI;EACE,yBAAqC;A9C2uS3C;;A8C5uSI;EACE,yBAAqC;A9C+uS3C;;A8ChvSI;EACE,yBAAqC;A9CmvS3C;;AClxSE;EACE,WAAW;EACX,YAAY;EACZ,cAAc;ADqxSlB;;A+CtxSA;EACE,sBAAsB;A/CyxSxB;;A+CvxSA;EACE,uBAAuB;A/C0xSzB;;AgDjySA;EACE,2BAA2B;AhDoyS7B;;AgDlySA;EACE,2BAA2B;AhDqyS7B;;AgDnySA;EACE,0BAA0B;EAC1B,8BAA8B;AhDsyShC;;AiDhzSA;EACE,2BAA2B;AjDmzS7B;;AkD/ySA;EACE,6BAA6B;AlDkzS/B;;AmDxzSA;EACE,oBAAoB;AnD2zStB;;AmDzzSA;EACE,qBAAqB;AnD4zSvB;;AmDjzSI;EACE,oBAA+B;AnDozSrC;;AmDjzSM;EACE,wBAA8C;AnDozStD;;AmDrzSM;EACE,0BAA8C;AnDwzStD;;AmDzzSM;EACE,2BAA8C;AnD4zStD;;AmD7zSM;EACE,yBAA8C;AnDg0StD;;AmD7zSM;EACE,yBAAyC;EACzC,0BAA2C;AnDg0SnD;;AmD7zSM;EACE,wBAAuC;EACvC,2BAA6C;AnDg0SrD;;AmD/0SI;EACE,0BAA+B;AnDk1SrC;;AmD/0SM;EACE,8BAA8C;AnDk1StD;;AmDn1SM;EACE,gCAA8C;AnDs1StD;;AmDv1SM;EACE,iCAA8C;AnD01StD;;AmD31SM;EACE,+BAA8C;AnD81StD;;AmD31SM;EACE,+BAAyC;EACzC,gCAA2C;AnD81SnD;;AmD31SM;EACE,8BAAuC;EACvC,iCAA6C;AnD81SrD;;AmD72SI;EACE,yBAA+B;AnDg3SrC;;AmD72SM;EACE,6BAA8C;AnDg3StD;;AmDj3SM;EACE,+BAA8C;AnDo3StD;;AmDr3SM;EACE,gCAA8C;AnDw3StD;;AmDz3SM;EACE,8BAA8C;AnD43StD;;AmDz3SM;EACE,8BAAyC;EACzC,+BAA2C;AnD43SnD;;AmDz3SM;EACE,6BAAuC;EACvC,gCAA6C;AnD43SrD;;AmD34SI;EACE,0BAA+B;AnD84SrC;;AmD34SM;EACE,8BAA8C;AnD84StD;;AmD/4SM;EACE,gCAA8C;AnDk5StD;;AmDn5SM;EACE,iCAA8C;AnDs5StD;;AmDv5SM;EACE,+BAA8C;AnD05StD;;AmDv5SM;EACE,+BAAyC;EACzC,gCAA2C;AnD05SnD;;AmDv5SM;EACE,8BAAuC;EACvC,iCAA6C;AnD05SrD;;AmDz6SI;EACE,uBAA+B;AnD46SrC;;AmDz6SM;EACE,2BAA8C;AnD46StD;;AmD76SM;EACE,6BAA8C;AnDg7StD;;AmDj7SM;EACE,8BAA8C;AnDo7StD;;AmDr7SM;EACE,4BAA8C;AnDw7StD;;AmDr7SM;EACE,4BAAyC;EACzC,6BAA2C;AnDw7SnD;;AmDr7SM;EACE,2BAAuC;EACvC,8BAA6C;AnDw7SrD;;AmDv8SI;EACE,yBAA+B;AnD08SrC;;AmDv8SM;EACE,6BAA8C;AnD08StD;;AmD38SM;EACE,+BAA8C;AnD88StD;;AmD/8SM;EACE,gCAA8C;AnDk9StD;;AmDn9SM;EACE,8BAA8C;AnDs9StD;;AmDn9SM;EACE,8BAAyC;EACzC,+BAA2C;AnDs9SnD;;AmDn9SM;EACE,6BAAuC;EACvC,gCAA6C;AnDs9SrD;;AmDr+SI;EACE,uBAA+B;AnDw+SrC;;AmDr+SM;EACE,2BAA8C;AnDw+StD;;AmDz+SM;EACE,6BAA8C;AnD4+StD;;AmD7+SM;EACE,8BAA8C;AnDg/StD;;AmDj/SM;EACE,4BAA8C;AnDo/StD;;AmDj/SM;EACE,4BAAyC;EACzC,6BAA2C;AnDo/SnD;;AmDj/SM;EACE,2BAAuC;EACvC,8BAA6C;AnDo/SrD;;AmDngTI;EACE,uBAA+B;AnDsgTrC;;AmDngTM;EACE,2BAA8C;AnDsgTtD;;AmDvgTM;EACE,6BAA8C;AnD0gTtD;;AmD3gTM;EACE,8BAA8C;AnD8gTtD;;AmD/gTM;EACE,4BAA8C;AnDkhTtD;;AmD/gTM;EACE,4BAAyC;EACzC,6BAA2C;AnDkhTnD;;AmD/gTM;EACE,2BAAuC;EACvC,8BAA6C;AnDkhTrD;;AmDjiTI;EACE,qBAA+B;AnDoiTrC;;AmDjiTM;EACE,yBAA8C;AnDoiTtD;;AmDriTM;EACE,2BAA8C;AnDwiTtD;;AmDziTM;EACE,4BAA8C;AnD4iTtD;;AmD7iTM;EACE,0BAA8C;AnDgjTtD;;AmD7iTM;EACE,0BAAyC;EACzC,2BAA2C;AnDgjTnD;;AmD7iTM;EACE,yBAAuC;EACvC,4BAA6C;AnDgjTrD;;AmD/jTI;EACE,2BAA+B;AnDkkTrC;;AmD/jTM;EACE,+BAA8C;AnDkkTtD;;AmDnkTM;EACE,iCAA8C;AnDskTtD;;AmDvkTM;EACE,kCAA8C;AnD0kTtD;;AmD3kTM;EACE,gCAA8C;AnD8kTtD;;AmD3kTM;EACE,gCAAyC;EACzC,iCAA2C;AnD8kTnD;;AmD3kTM;EACE,+BAAuC;EACvC,kCAA6C;AnD8kTrD;;AmD7lTI;EACE,0BAA+B;AnDgmTrC;;AmD7lTM;EACE,8BAA8C;AnDgmTtD;;AmDjmTM;EACE,gCAA8C;AnDomTtD;;AmDrmTM;EACE,iCAA8C;AnDwmTtD;;AmDzmTM;EACE,+BAA8C;AnD4mTtD;;AmDzmTM;EACE,+BAAyC;EACzC,gCAA2C;AnD4mTnD;;AmDzmTM;EACE,8BAAuC;EACvC,iCAA6C;AnD4mTrD;;AmD3nTI;EACE,2BAA+B;AnD8nTrC;;AmD3nTM;EACE,+BAA8C;AnD8nTtD;;AmD/nTM;EACE,iCAA8C;AnDkoTtD;;AmDnoTM;EACE,kCAA8C;AnDsoTtD;;AmDvoTM;EACE,gCAA8C;AnD0oTtD;;AmDvoTM;EACE,gCAAyC;EACzC,iCAA2C;AnD0oTnD;;AmDvoTM;EACE,+BAAuC;EACvC,kCAA6C;AnD0oTrD;;AmDzpTI;EACE,wBAA+B;AnD4pTrC;;AmDzpTM;EACE,4BAA8C;AnD4pTtD;;AmD7pTM;EACE,8BAA8C;AnDgqTtD;;AmDjqTM;EACE,+BAA8C;AnDoqTtD;;AmDrqTM;EACE,6BAA8C;AnDwqTtD;;AmDrqTM;EACE,6BAAyC;EACzC,8BAA2C;AnDwqTnD;;AmDrqTM;EACE,4BAAuC;EACvC,+BAA6C;AnDwqTrD;;AmDvrTI;EACE,0BAA+B;AnD0rTrC;;AmDvrTM;EACE,8BAA8C;AnD0rTtD;;AmD3rTM;EACE,gCAA8C;AnD8rTtD;;AmD/rTM;EACE,iCAA8C;AnDksTtD;;AmDnsTM;EACE,+BAA8C;AnDssTtD;;AmDnsTM;EACE,+BAAyC;EACzC,gCAA2C;AnDssTnD;;AmDnsTM;EACE,8BAAuC;EACvC,iCAA6C;AnDssTrD;;AmDrtTI;EACE,wBAA+B;AnDwtTrC;;AmDrtTM;EACE,4BAA8C;AnDwtTtD;;AmDztTM;EACE,8BAA8C;AnD4tTtD;;AmD7tTM;EACE,+BAA8C;AnDguTtD;;AmDjuTM;EACE,6BAA8C;AnDouTtD;;AmDjuTM;EACE,6BAAyC;EACzC,8BAA2C;AnDouTnD;;AmDjuTM;EACE,4BAAuC;EACvC,+BAA6C;AnDouTrD;;AmDnvTI;EACE,wBAA+B;AnDsvTrC;;AmDnvTM;EACE,4BAA8C;AnDsvTtD;;AmDvvTM;EACE,8BAA8C;AnD0vTtD;;AmD3vTM;EACE,+BAA8C;AnD8vTtD;;AmD/vTM;EACE,6BAA8C;AnDkwTtD;;AmD/vTM;EACE,6BAAyC;EACzC,8BAA2C;AnDkwTnD;;AmD/vTM;EACE,4BAAuC;EACvC,+BAA6C;AnDkwTrD;;AoD3xTI;EACE,0BAA2B;ApD8xTjC;;AoD/xTI;EACE,4BAA2B;ApDkyTjC;;AoDnyTI;EACE,0BAA2B;ApDsyTjC;;AoDvyTI;EACE,4BAA2B;ApD0yTjC;;AoD3yTI;EACE,6BAA2B;ApD8yTjC;;AoD/yTI;EACE,0BAA2B;ApDkzTjC;;AoDnzTI;EACE,6BAA2B;ApDszTjC;;ACttTE;EmDjGE;IACE,0BAA2B;EpD2zT/B;EoD5zTE;IACE,4BAA2B;EpD8zT/B;EoD/zTE;IACE,0BAA2B;EpDi0T/B;EoDl0TE;IACE,4BAA2B;EpDo0T/B;EoDr0TE;IACE,6BAA2B;EpDu0T/B;EoDx0TE;IACE,0BAA2B;EpD00T/B;EoD30TE;IACE,6BAA2B;EpD60T/B;AACF;;AC1uTE;EmDrGE;IACE,0BAA2B;EpDm1T/B;EoDp1TE;IACE,4BAA2B;EpDs1T/B;EoDv1TE;IACE,0BAA2B;EpDy1T/B;EoD11TE;IACE,4BAA2B;EpD41T/B;EoD71TE;IACE,6BAA2B;EpD+1T/B;EoDh2TE;IACE,0BAA2B;EpDk2T/B;EoDn2TE;IACE,6BAA2B;EpDq2T/B;AACF;;AC1vTE;EmD7GE;IACE,0BAA2B;EpD22T/B;EoD52TE;IACE,4BAA2B;EpD82T/B;EoD/2TE;IACE,0BAA2B;EpDi3T/B;EoDl3TE;IACE,4BAA2B;EpDo3T/B;EoDr3TE;IACE,6BAA2B;EpDu3T/B;EoDx3TE;IACE,0BAA2B;EpD03T/B;EoD33TE;IACE,6BAA2B;EpD63T/B;AACF;;AC9wTE;EmDjHE;IACE,0BAA2B;EpDm4T/B;EoDp4TE;IACE,4BAA2B;EpDs4T/B;EoDv4TE;IACE,0BAA2B;EpDy4T/B;EoD14TE;IACE,4BAA2B;EpD44T/B;EoD74TE;IACE,6BAA2B;EpD+4T/B;EoDh5TE;IACE,0BAA2B;EpDk5T/B;EoDn5TE;IACE,6BAA2B;EpDq5T/B;AACF;;ACvxTI;EmDhIA;IACE,0BAA2B;EpD25T/B;EoD55TE;IACE,4BAA2B;EpD85T/B;EoD/5TE;IACE,0BAA2B;EpDi6T/B;EoDl6TE;IACE,4BAA2B;EpDo6T/B;EoDr6TE;IACE,6BAA2B;EpDu6T/B;EoDx6TE;IACE,0BAA2B;EpD06T/B;EoD36TE;IACE,6BAA2B;EpD66T/B;AACF;;AChyTI;EmD/IA;IACE,0BAA2B;EpDm7T/B;EoDp7TE;IACE,4BAA2B;EpDs7T/B;EoDv7TE;IACE,0BAA2B;EpDy7T/B;EoD17TE;IACE,4BAA2B;EpD47T/B;EoD77TE;IACE,6BAA2B;EpD+7T/B;EoDh8TE;IACE,0BAA2B;EpDk8T/B;EoDn8TE;IACE,6BAA2B;EpDq8T/B;AACF;;AoD76TE;EACE,6BAAqC;ApDg7TzC;;AoDj7TE;EACE,8BAAqC;ApDo7TzC;;AoDr7TE;EACE,2BAAqC;ApDw7TzC;;AoDz7TE;EACE,4BAAqC;ApD47TzC;;ACt3TE;EmDlEE;IACE,6BAAqC;EpD47TzC;AACF;;ACx3TE;EmDnEE;IACE,6BAAqC;EpD+7TzC;AACF;;AC13TE;EmDpEE;IACE,6BAAqC;EpDk8TzC;AACF;;AC53TE;EmDrEE;IACE,6BAAqC;EpDq8TzC;AACF;;AC93TE;EmDtEE;IACE,6BAAqC;EpDw8TzC;AACF;;AC/3TI;EmDxEA;IACE,6BAAqC;EpD28TzC;AACF;;AC33TI;EmD/EA;IACE,6BAAqC;EpD88TzC;AACF;;AC53TI;EmDjFA;IACE,6BAAqC;EpDi9TzC;AACF;;ACx3TI;EmDxFA;IACE,6BAAqC;EpDo9TzC;AACF;;AC56TE;EmDlEE;IACE,8BAAqC;EpDk/TzC;AACF;;AC96TE;EmDnEE;IACE,8BAAqC;EpDq/TzC;AACF;;ACh7TE;EmDpEE;IACE,8BAAqC;EpDw/TzC;AACF;;ACl7TE;EmDrEE;IACE,8BAAqC;EpD2/TzC;AACF;;ACp7TE;EmDtEE;IACE,8BAAqC;EpD8/TzC;AACF;;ACr7TI;EmDxEA;IACE,8BAAqC;EpDigUzC;AACF;;ACj7TI;EmD/EA;IACE,8BAAqC;EpDogUzC;AACF;;ACl7TI;EmDjFA;IACE,8BAAqC;EpDugUzC;AACF;;AC96TI;EmDxFA;IACE,8BAAqC;EpD0gUzC;AACF;;ACl+TE;EmDlEE;IACE,2BAAqC;EpDwiUzC;AACF;;ACp+TE;EmDnEE;IACE,2BAAqC;EpD2iUzC;AACF;;ACt+TE;EmDpEE;IACE,2BAAqC;EpD8iUzC;AACF;;ACx+TE;EmDrEE;IACE,2BAAqC;EpDijUzC;AACF;;AC1+TE;EmDtEE;IACE,2BAAqC;EpDojUzC;AACF;;AC3+TI;EmDxEA;IACE,2BAAqC;EpDujUzC;AACF;;ACv+TI;EmD/EA;IACE,2BAAqC;EpD0jUzC;AACF;;ACx+TI;EmDjFA;IACE,2BAAqC;EpD6jUzC;AACF;;ACp+TI;EmDxFA;IACE,2BAAqC;EpDgkUzC;AACF;;ACxhUE;EmDlEE;IACE,4BAAqC;EpD8lUzC;AACF;;AC1hUE;EmDnEE;IACE,4BAAqC;EpDimUzC;AACF;;AC5hUE;EmDpEE;IACE,4BAAqC;EpDomUzC;AACF;;AC9hUE;EmDrEE;IACE,4BAAqC;EpDumUzC;AACF;;AChiUE;EmDtEE;IACE,4BAAqC;EpD0mUzC;AACF;;ACjiUI;EmDxEA;IACE,4BAAqC;EpD6mUzC;AACF;;AC7hUI;EmD/EA;IACE,4BAAqC;EpDgnUzC;AACF;;AC9hUI;EmDjFA;IACE,4BAAqC;EpDmnUzC;AACF;;AC1hUI;EmDxFA;IACE,4BAAqC;EpDsnUzC;AACF;;AoDrnUA;EACE,qCAAqC;ApDwnUvC;;AoDtnUA;EACE,oCAAoC;ApDynUtC;;AoDvnUA;EACE,oCAAoC;ApD0nUtC;;AoDxnUA;EACE,6BAA6B;ApD2nU/B;;AoDznUA;EACE,qCAAqC;ApD4nUvC;;AoD1nUA;EACE,2BAAqC;ApD6nUvC;;AoD5nUA;EACE,2BAAsC;ApD+nUxC;;AoD9nUA;EACE,2BAAsC;ApDioUxC;;AoDhoUA;EACE,2BAAwC;ApDmoU1C;;AoDloUA;EACE,2BAAoC;ApDqoUtC;;AoDnoUA;EACE,+LAAuC;ApDsoUzC;;AoDpoUA;EACE,+LAAyC;ApDuoU3C;;AoDroUA;EACE,+LAA0C;ApDwoU5C;;AoDtoUA;EACE,iCAAyC;ApDyoU3C;;AoDvoUA;EACE,iCAAoC;ApD0oUtC;;AqD3uUE;EACE,yBAA+B;ArD8uUnC;;AC9oUE;EoD9FE;IACE,yBAA+B;ErDgvUnC;AACF;;AChpUE;EoD/FE;IACE,yBAA+B;ErDmvUnC;AACF;;AClpUE;EoDhGE;IACE,yBAA+B;ErDsvUnC;AACF;;ACppUE;EoDjGE;IACE,yBAA+B;ErDyvUnC;AACF;;ACtpUE;EoDlGE;IACE,yBAA+B;ErD4vUnC;AACF;;ACvpUI;EoDpGA;IACE,yBAA+B;ErD+vUnC;AACF;;ACnpUI;EoD3GA;IACE,yBAA+B;ErDkwUnC;AACF;;ACppUI;EoD7GA;IACE,yBAA+B;ErDqwUnC;AACF;;AChpUI;EoDpHA;IACE,yBAA+B;ErDwwUnC;AACF;;AqDryUE;EACE,wBAA+B;ArDwyUnC;;ACxsUE;EoD9FE;IACE,wBAA+B;ErD0yUnC;AACF;;AC1sUE;EoD/FE;IACE,wBAA+B;ErD6yUnC;AACF;;AC5sUE;EoDhGE;IACE,wBAA+B;ErDgzUnC;AACF;;AC9sUE;EoDjGE;IACE,wBAA+B;ErDmzUnC;AACF;;AChtUE;EoDlGE;IACE,wBAA+B;ErDszUnC;AACF;;ACjtUI;EoDpGA;IACE,wBAA+B;ErDyzUnC;AACF;;AC7sUI;EoD3GA;IACE,wBAA+B;ErD4zUnC;AACF;;AC9sUI;EoD7GA;IACE,wBAA+B;ErD+zUnC;AACF;;AC1sUI;EoDpHA;IACE,wBAA+B;ErDk0UnC;AACF;;AqD/1UE;EACE,0BAA+B;ArDk2UnC;;AClwUE;EoD9FE;IACE,0BAA+B;ErDo2UnC;AACF;;ACpwUE;EoD/FE;IACE,0BAA+B;ErDu2UnC;AACF;;ACtwUE;EoDhGE;IACE,0BAA+B;ErD02UnC;AACF;;ACxwUE;EoDjGE;IACE,0BAA+B;ErD62UnC;AACF;;AC1wUE;EoDlGE;IACE,0BAA+B;ErDg3UnC;AACF;;AC3wUI;EoDpGA;IACE,0BAA+B;ErDm3UnC;AACF;;ACvwUI;EoD3GA;IACE,0BAA+B;ErDs3UnC;AACF;;ACxwUI;EoD7GA;IACE,0BAA+B;ErDy3UnC;AACF;;ACpwUI;EoDpHA;IACE,0BAA+B;ErD43UnC;AACF;;AqDz5UE;EACE,gCAA+B;ArD45UnC;;AC5zUE;EoD9FE;IACE,gCAA+B;ErD85UnC;AACF;;AC9zUE;EoD/FE;IACE,gCAA+B;ErDi6UnC;AACF;;ACh0UE;EoDhGE;IACE,gCAA+B;ErDo6UnC;AACF;;ACl0UE;EoDjGE;IACE,gCAA+B;ErDu6UnC;AACF;;ACp0UE;EoDlGE;IACE,gCAA+B;ErD06UnC;AACF;;ACr0UI;EoDpGA;IACE,gCAA+B;ErD66UnC;AACF;;ACj0UI;EoD3GA;IACE,gCAA+B;ErDg7UnC;AACF;;ACl0UI;EoD7GA;IACE,gCAA+B;ErDm7UnC;AACF;;AC9zUI;EoDpHA;IACE,gCAA+B;ErDs7UnC;AACF;;AqDn9UE;EACE,+BAA+B;ArDs9UnC;;ACt3UE;EoD9FE;IACE,+BAA+B;ErDw9UnC;AACF;;ACx3UE;EoD/FE;IACE,+BAA+B;ErD29UnC;AACF;;AC13UE;EoDhGE;IACE,+BAA+B;ErD89UnC;AACF;;AC53UE;EoDjGE;IACE,+BAA+B;ErDi+UnC;AACF;;AC93UE;EoDlGE;IACE,+BAA+B;ErDo+UnC;AACF;;AC/3UI;EoDpGA;IACE,+BAA+B;ErDu+UnC;AACF;;AC33UI;EoD3GA;IACE,+BAA+B;ErD0+UnC;AACF;;AC53UI;EoD7GA;IACE,+BAA+B;ErD6+UnC;AACF;;ACx3UI;EoDpHA;IACE,+BAA+B;ErDg/UnC;AACF;;AqD/+UA;EACE,wBAAwB;ArDk/U1B;;AqDh/UA;EACE,uBAAuB;EACvB,iCAAiC;EACjC,yBAAyB;EACzB,2BAA2B;EAC3B,qBAAqB;EACrB,6BAA6B;EAC7B,8BAA8B;EAC9B,wBAAwB;ArDm/U1B;;AC37UE;EoDrDA;IACE,wBAAwB;ErDo/U1B;AACF;;AC77UE;EoDrDA;IACE,wBAAwB;ErDs/U1B;AACF;;AC/7UE;EoDrDA;IACE,wBAAwB;ErDw/U1B;AACF;;ACj8UE;EoDrDA;IACE,wBAAwB;ErD0/U1B;AACF;;ACn8UE;EoDrDA;IACE,wBAAwB;ErD4/U1B;AACF;;ACp8UI;EoDtDF;IACE,wBAAwB;ErD8/U1B;AACF;;ACh8UI;EoD5DF;IACE,wBAAwB;ErDggV1B;AACF;;ACj8UI;EoD7DF;IACE,wBAAwB;ErDkgV1B;AACF;;AC77UI;EoDnEF;IACE,wBAAwB;ErDogV1B;AACF;;AqDngVA;EACE,6BAA6B;ArDsgV/B;;ACr/UE;EoDdA;IACE,6BAA6B;ErDugV/B;AACF;;ACv/UE;EoDdA;IACE,6BAA6B;ErDygV/B;AACF;;ACz/UE;EoDdA;IACE,6BAA6B;ErD2gV/B;AACF;;AC3/UE;EoDdA;IACE,6BAA6B;ErD6gV/B;AACF;;AC7/UE;EoDdA;IACE,6BAA6B;ErD+gV/B;AACF;;AC9/UI;EoDfF;IACE,6BAA6B;ErDihV/B;AACF;;AC1/UI;EoDrBF;IACE,6BAA6B;ErDmhV/B;AACF;;AC3/UI;EoDtBF;IACE,6BAA6B;ErDqhV/B;AACF;;ACv/UI;EoD5BF;IACE,6BAA6B;ErDuhV/B;AACF;;AsDjpVA,iBAAA;ACWA;EACE,oBAAoB;EACpB,aAAa;EACb,sBAAsB;EACtB,8BAA8B;AvD0oVhC;;AuD9oVA;EAMI,gBAAgB;AvD4oVpB;;AuDlpVA;EASM,mBAAmB;AvD6oVzB;;AuDtpVA;EAeM,uBxDXyB;EwDYzB,cxDzBuB;ACoqV7B;;AuD3pVA;;EAmBQ,cAAc;AvD6oVtB;;AuDhqVA;EAqBQ,cxD9BqB;AC6qV7B;;AuDpqVA;EAuBQ,4BxDhCqB;ACirV7B;;AuDxqVA;;EA0BU,cxDnCmB;ACsrV7B;;ACtkVE;EsDvGF;IA6BU,uBxDzBqB;EC8qV7B;AACF;;AuDnrVA;;EAgCQ,4BxDzCqB;ACisV7B;;AuDxrVA;;;EAqCU,yB7C4DuB;E6C3DvB,cxD/CmB;ACwsV7B;;AuD/rVA;EAyCU,cxDlDmB;EwDmDnB,YAAY;AvD0pVtB;;AuDpsVA;EA4CY,UAAU;AvD4pVtB;;AuDxsVA;EA+CY,uBAAwB;EACxB,UAAU;AvD6pVtB;;AuD7sVA;EAoDY,cxD7DiB;AC0tV7B;;AuDjtVA;EAsDc,uCxD/De;AC8tV7B;;AuDrtVA;EA0Dc,yBxDnEe;EwDoEf,qBxDpEe;EwDqEf,YxDxDiB;ACutV/B;;AuD3tVA;EAkEU,4EAAyG;AvD6pVnH;;ACpoVE;EsD3FF;IAqEc,4EAAyG;EvD+pVrH;AACF;;AuDruVA;EAeM,yBxDxBuB;EwDyBvB,YxDZyB;ACsuV/B;;AuD1uVA;;EAmBQ,cAAc;AvD4tVtB;;AuD/uVA;EAqBQ,YxDjBuB;AC+uV/B;;AuDnvVA;EAuBQ,+BxDnBuB;ACmvV/B;;AuDvvVA;;EA0BU,YxDtBqB;ACwvV/B;;ACrpVE;EsDvGF;IA6BU,yBxDtCmB;EC0wV3B;AACF;;AuDlwVA;;EAgCQ,+BxD5BuB;ACmwV/B;;AuDvwVA;;;EAqCU,uB7C4DuB;E6C3DvB,YxDlCqB;AC0wV/B;;AuD9wVA;EAyCU,YxDrCqB;EwDsCrB,YAAY;AvDyuVtB;;AuDnxVA;EA4CY,UAAU;AvD2uVtB;;AuDvxVA;EA+CY,yBAAwB;EACxB,UAAU;AvD4uVtB;;AuD5xVA;EAoDY,YxDhDmB;AC4xV/B;;AuDhyVA;EAsDc,uCxD/De;AC6yV7B;;AuDpyVA;EA0Dc,uBxDtDiB;EwDuDjB,mBxDvDiB;EwDwDjB,cxDrEe;ACmzV7B;;AuD1yVA;EAkEU,8EAAyG;AvD4uVnH;;ACntVE;EsD3FF;IAqEc,8EAAyG;EvD8uVrH;AACF;;AuDpzVA;EAeM,4BxDbwB;EwDcxB,yB7CqDe;AVovVrB;;AuDzzVA;;EAmBQ,cAAc;AvD2yVtB;;AuD9zVA;EAqBQ,yB7CgDa;AV6vVrB;;AuDl0VA;EAuBQ,yB7C8Ca;AViwVrB;;AuDt0VA;;EA0BU,yB7C2CW;AVswVrB;;ACpuVE;EsDvGF;IA6BU,4BxD3BoB;EC80V5B;AACF;;AuDj1VA;;EAgCQ,yB7CqCa;AVixVrB;;AuDt1VA;;;EAqCU,yB7C4DuB;E6C3DvB,yB7C+BW;AVwxVrB;;AuD71VA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDwzVtB;;AuDl2VA;EA4CY,UAAU;AvD0zVtB;;AuDt2VA;EA+CY,4BAAwB;EACxB,UAAU;AvD2zVtB;;AuD32VA;EAoDY,yB7CiBS;AV0yVrB;;AuD/2VA;EAsDc,uCxD/De;AC43V7B;;AuDn3VA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,iBxD1DgB;ACu3V9B;;AuDz3VA;EAkEU,iFAAyG;AvD2zVnH;;AClyVE;EsD3FF;IAqEc,iFAAyG;EvD6zVrH;AACF;;AuDn4VA;EAeM,yBxDpBwB;EwDqBxB,W7CuDU;AVi0VhB;;AuDx4VA;;EAmBQ,cAAc;AvD03VtB;;AuD74VA;EAqBQ,W7CkDQ;AV00VhB;;AuDj5VA;EAuBQ,+B7CgDQ;AV80VhB;;AuDr5VA;;EA0BU,W7C6CM;AVm1VhB;;ACnzVE;EsDvGF;IA6BU,yBxDlCoB;ECo6V5B;AACF;;AuDh6VA;;EAgCQ,+B7CuCQ;AV81VhB;;AuDr6VA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVq2VhB;;AuD56VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDu4VtB;;AuDj7VA;EA4CY,UAAU;AvDy4VtB;;AuDr7VA;EA+CY,yBAAwB;EACxB,UAAU;AvD04VtB;;AuD17VA;EAoDY,W7CmBI;AVu3VhB;;AuD97VA;EAsDc,uCxD/De;AC28V7B;;AuDl8VA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjEgB;AC68V9B;;AuDx8VA;EAkEU,gFAAyG;AvD04VnH;;ACj3VE;EsD3FF;IAqEc,gFAAyG;EvD44VrH;AACF;;AuDl9VA;EAeM,yBxDN4B;EwDO5B,W7CuDU;AVg5VhB;;AuDv9VA;;EAmBQ,cAAc;AvDy8VtB;;AuD59VA;EAqBQ,W7CkDQ;AVy5VhB;;AuDh+VA;EAuBQ,+B7CgDQ;AV65VhB;;AuDp+VA;;EA0BU,W7C6CM;AVk6VhB;;ACl4VE;EsDvGF;IA6BU,yBxDpBwB;ECq+VhC;AACF;;AuD/+VA;;EAgCQ,+B7CuCQ;AV66VhB;;AuDp/VA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVo7VhB;;AuD3/VA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDs9VtB;;AuDhgWA;EA4CY,UAAU;AvDw9VtB;;AuDpgWA;EA+CY,yBAAwB;EACxB,UAAU;AvDy9VtB;;AuDzgWA;EAoDY,W7CmBI;AVs8VhB;;AuD7gWA;EAsDc,uCxD/De;AC0hW7B;;AuDjhWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDnDoB;AC8gWlC;;AuDvhWA;EAkEU,gFAAyG;AvDy9VnH;;ACh8VE;EsD3FF;IAqEc,gFAAyG;EvD29VrH;AACF;;AuDjiWA;EAeM,yBxDJ4B;EwDK5B,W7CuDU;AV+9VhB;;AuDtiWA;;EAmBQ,cAAc;AvDwhWtB;;AuD3iWA;EAqBQ,W7CkDQ;AVw+VhB;;AuD/iWA;EAuBQ,+B7CgDQ;AV4+VhB;;AuDnjWA;;EA0BU,W7C6CM;AVi/VhB;;ACj9VE;EsDvGF;IA6BU,yBxDlBwB;ECkjWhC;AACF;;AuD9jWA;;EAgCQ,+B7CuCQ;AV4/VhB;;AuDnkWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVmgWhB;;AuD1kWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDqiWtB;;AuD/kWA;EA4CY,UAAU;AvDuiWtB;;AuDnlWA;EA+CY,yBAAwB;EACxB,UAAU;AvDwiWtB;;AuDxlWA;EAoDY,W7CmBI;AVqhWhB;;AuD5lWA;EAsDc,uCxD/De;ACymW7B;;AuDhmWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDjDoB;AC2lWlC;;AuDtmWA;EAkEU,gFAAyG;AvDwiWnH;;AC/gWE;EsD3FF;IAqEc,gFAAyG;EvD0iWrH;AACF;;AuDhnWA;EAeM,yBxDL4B;EwDM5B,W7CuDU;AV8iWhB;;AuDrnWA;;EAmBQ,cAAc;AvDumWtB;;AuD1nWA;EAqBQ,W7CkDQ;AVujWhB;;AuD9nWA;EAuBQ,+B7CgDQ;AV2jWhB;;AuDloWA;;EA0BU,W7C6CM;AVgkWhB;;AChiWE;EsDvGF;IA6BU,yBxDnBwB;ECkoWhC;AACF;;AuD7oWA;;EAgCQ,+B7CuCQ;AV2kWhB;;AuDlpWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AVklWhB;;AuDzpWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDonWtB;;AuD9pWA;EA4CY,UAAU;AvDsnWtB;;AuDlqWA;EA+CY,yBAAwB;EACxB,UAAU;AvDunWtB;;AuDvqWA;EAoDY,W7CmBI;AVomWhB;;AuD3qWA;EAsDc,uCxD/De;ACwrW7B;;AuD/qWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDlDoB;AC2qWlC;;AuDrrWA;EAkEU,gFAAyG;AvDunWnH;;AC9lWE;EsD3FF;IAqEc,gFAAyG;EvDynWrH;AACF;;AuD/rWA;EAeM,yBxDP4B;EwDQ5B,W7CuDU;AV6nWhB;;AuDpsWA;;EAmBQ,cAAc;AvDsrWtB;;AuDzsWA;EAqBQ,W7CkDQ;AVsoWhB;;AuD7sWA;EAuBQ,+B7CgDQ;AV0oWhB;;AuDjtWA;;EA0BU,W7C6CM;AV+oWhB;;AC/mWE;EsDvGF;IA6BU,yBxDrBwB;ECmtWhC;AACF;;AuD5tWA;;EAgCQ,+B7CuCQ;AV0pWhB;;AuDjuWA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AViqWhB;;AuDxuWA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDmsWtB;;AuD7uWA;EA4CY,UAAU;AvDqsWtB;;AuDjvWA;EA+CY,yBAAwB;EACxB,UAAU;AvDssWtB;;AuDtvWA;EAoDY,W7CmBI;AVmrWhB;;AuD1vWA;EAsDc,uCxD/De;ACuwW7B;;AuD9vWA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxDpDoB;AC4vWlC;;AuDpwWA;EAkEU,gFAAyG;AvDssWnH;;AC7qWE;EsD3FF;IAqEc,gFAAyG;EvDwsWrH;AACF;;AuD9wWA;EAeM,yBxDR4B;EwDS5B,yB7CqDe;AV8sWrB;;AuDnxWA;;EAmBQ,cAAc;AvDqwWtB;;AuDxxWA;EAqBQ,yB7CgDa;AVutWrB;;AuD5xWA;EAuBQ,yB7C8Ca;AV2tWrB;;AuDhyWA;;EA0BU,yB7C2CW;AVguWrB;;AC9rWE;EsDvGF;IA6BU,yBxDtBwB;ECmyWhC;AACF;;AuD3yWA;;EAgCQ,yB7CqCa;AV2uWrB;;AuDhzWA;;;EAqCU,yB7C4DuB;E6C3DvB,yB7C+BW;AVkvWrB;;AuDvzWA;EAyCU,yB7C4BW;E6C3BX,YAAY;AvDkxWtB;;AuD5zWA;EA4CY,UAAU;AvDoxWtB;;AuDh0WA;EA+CY,yBAAwB;EACxB,UAAU;AvDqxWtB;;AuDr0WA;EAoDY,yB7CiBS;AVowWrB;;AuDz0WA;EAsDc,uCxD/De;ACs1W7B;;AuD70WA;EA0Dc,oC7CWO;E6CVP,gC7CUO;E6CTP,cxDrDoB;AC40WlC;;AuDn1WA;EAkEU,gFAAyG;AvDqxWnH;;AC5vWE;EsD3FF;IAqEc,gFAAyG;EvDuxWrH;AACF;;AuD71WA;EAeM,yBxDF2B;EwDG3B,W7CuDU;AV2xWhB;;AuDl2WA;;EAmBQ,cAAc;AvDo1WtB;;AuDv2WA;EAqBQ,W7CkDQ;AVoyWhB;;AuD32WA;EAuBQ,+B7CgDQ;AVwyWhB;;AuD/2WA;;EA0BU,W7C6CM;AV6yWhB;;AC7wWE;EsDvGF;IA6BU,yBxDhBuB;EC42W/B;AACF;;AuD13WA;;EAgCQ,+B7CuCQ;AVwzWhB;;AuD/3WA;;;EAqCU,yB7C4DuB;E6C3DvB,W7CiCM;AV+zWhB;;AuDt4WA;EAyCU,W7C8BM;E6C7BN,YAAY;AvDi2WtB;;AuD34WA;EA4CY,UAAU;AvDm2WtB;;AuD/4WA;EA+CY,yBAAwB;EACxB,UAAU;AvDo2WtB;;AuDp5WA;EAoDY,W7CmBI;AVi1WhB;;AuDx5WA;EAsDc,uCxD/De;ACq6W7B;;AuD55WA;EA0Dc,sB7CaE;E6CZF,kB7CYE;E6CXF,cxD/CmB;ACq5WjC;;AuDl6WA;EAkEU,gFAAyG;AvDo2WnH;;AC30WE;EsD3FF;IAqEc,gFAAyG;EvDs2WrH;AACF;;AuD56WA;EAyEM,eAhF0B;AvDu7WhC;;ACj1WE;EsD/FF;IA6EQ,oBAnF8B;EvD27WpC;AACF;;ACv1WE;EsD/FF;IAiFQ,mBAtF4B;EvDg8WlC;AACF;;AuD57WA;EAsFM,mBAAmB;EACnB,aAAa;AvD02WnB;;AuDj8WA;EAyFQ,YAAY;EACZ,cAAc;AvD42WtB;;AuDt8WA;EA4FI,gBAAgB;AvD82WpB;;AuD18WA;EA8FI,iBAAiB;AvDg3WrB;;AuD52WA;EAEE,gBAAgB;AvD82WlB;;AuDh3WA;EAII,SAAS;EACT,gBAAgB;EAChB,eAAe;EACf,kBAAkB;EAClB,QAAQ;EACR,qCAAqC;AvDg3WzC;;AuDz3WA;EAYI,YAAY;AvDi3WhB;;ACp4WE;EsDOF;IAeI,aAAa;EvDm3Wf;AACF;;AuDl3WA;EACE,kBAAkB;AvDq3WpB;;AC94WE;EsDwBF;IAKM,aAAa;EvDs3WjB;EuD33WF;IAOQ,sBAAsB;EvDu3W5B;AACF;;ACn5WE;EsDoBF;IASI,aAAa;IACb,uBAAuB;EvD23WzB;EuDr4WF;ItDsDI,oBsD1CwC;EvD43W1C;AACF;;AuDz3WA;;EAEE,YAAY;EACZ,cAAc;AvD43WhB;;AuD13WA;EACE,YAAY;EACZ,cAAc;EACd,oBApJ6B;AvDihX/B;;ACz6WE;EsDyCF;IAKI,kBArJgC;EvDqhXlC;AACF;;AwDlhXA;EACE,oBAN2B;AxD2hX7B;;ACv6WE;EuD/GF;IAII,kBAR+B;ExD+hXjC;EwD3hXF;IAOM,oBAV8B;ExDiiXlC;EwD9hXF;IASM,mBAX4B;ExDmiXhC;AACF;;AyDniXA;EACE,yB1DO4B;E0DN5B,yBAJ+B;AzD0iXjC","file":"bulma.css"} \ No newline at end of file diff --git a/templ/examples/counter/assets/css/bulma.min.css b/templ/examples/counter/assets/css/bulma.min.css new file mode 100644 index 0000000..86ad2ff --- /dev/null +++ b/templ/examples/counter/assets/css/bulma.min.css @@ -0,0 +1 @@ +/*! bulma.io v0.9.4 | MIT License | github.com/jgthms/bulma */.button,.file-cta,.file-name,.input,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.select select,.textarea{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(.5em - 1px);padding-left:calc(.75em - 1px);padding-right:calc(.75em - 1px);padding-top:calc(.5em - 1px);position:relative;vertical-align:top}.button:active,.button:focus,.file-cta:active,.file-cta:focus,.file-name:active,.file-name:focus,.input:active,.input:focus,.is-active.button,.is-active.file-cta,.is-active.file-name,.is-active.input,.is-active.pagination-ellipsis,.is-active.pagination-link,.is-active.pagination-next,.is-active.pagination-previous,.is-active.textarea,.is-focused.button,.is-focused.file-cta,.is-focused.file-name,.is-focused.input,.is-focused.pagination-ellipsis,.is-focused.pagination-link,.is-focused.pagination-next,.is-focused.pagination-previous,.is-focused.textarea,.pagination-ellipsis:active,.pagination-ellipsis:focus,.pagination-link:active,.pagination-link:focus,.pagination-next:active,.pagination-next:focus,.pagination-previous:active,.pagination-previous:focus,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{outline:0}.button[disabled],.file-cta[disabled],.file-name[disabled],.input[disabled],.pagination-ellipsis[disabled],.pagination-link[disabled],.pagination-next[disabled],.pagination-previous[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .button,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .input,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-previous,fieldset[disabled] .select select,fieldset[disabled] .textarea{cursor:not-allowed}.breadcrumb,.button,.file,.is-unselectable,.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous,.tabs{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid transparent;border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:.625em;margin-top:-.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:.625em}.block:not(:last-child),.box:not(:last-child),.breadcrumb:not(:last-child),.content:not(:last-child),.level:not(:last-child),.message:not(:last-child),.notification:not(:last-child),.pagination:not(:last-child),.progress:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.tabs:not(:last-child),.title:not(:last-child){margin-bottom:1.5rem}.delete,.modal-close{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:0;position:relative;vertical-align:top;width:20px}.delete::after,.delete::before,.modal-close::after,.modal-close::before{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.delete::before,.modal-close::before{height:2px;width:50%}.delete::after,.modal-close::after{height:50%;width:2px}.delete:focus,.delete:hover,.modal-close:focus,.modal-close:hover{background-color:rgba(10,10,10,.3)}.delete:active,.modal-close:active{background-color:rgba(10,10,10,.4)}.is-small.delete,.is-small.modal-close{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.delete,.is-medium.modal-close{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.delete,.is-large.modal-close{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.button.is-loading::after,.control.is-loading::after,.loader,.select.is-loading::after{-webkit-animation:spinAround .5s infinite linear;animation:spinAround .5s infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img,.is-overlay,.modal,.modal-background{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:scroll;text-rendering:optimizeLegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#4a4a4a;font-size:1em;font-weight:400;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:#f5f5f5;color:#da1039;font-size:.875em;font-weight:400;padding:.25em .5em .25em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type=checkbox],input[type=radio]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#363636;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#4a4a4a;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#363636}@-webkit-keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}@keyframes spinAround{from{transform:rotate(0)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;display:block;padding:1.25rem}a.box:focus,a.box:hover{box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px #485fc7}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2),0 0 0 1px #485fc7}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#363636;cursor:pointer;justify-content:center;padding-bottom:calc(.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-large,.button .icon.is-medium,.button .icon.is-small{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-.5em - 1px);margin-right:calc(-.5em - 1px)}.button.is-hovered,.button:hover{border-color:#b5b5b5;color:#363636}.button.is-focused,.button:focus{border-color:#485fc7;color:#363636}.button.is-focused:not(:active),.button:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-active,.button:active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#4a4a4a;text-decoration:underline}.button.is-text.is-focused,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text:hover{background-color:#f5f5f5;color:#363636}.button.is-text.is-active,.button.is-text:active{background-color:#e8e8e8;color:#363636}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:0 0;border-color:transparent;color:#485fc7;text-decoration:none}.button.is-ghost.is-hovered,.button.is-ghost:hover{color:#485fc7;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white.is-hovered,.button.is-white:hover{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white.is-focused,.button.is-white:focus{border-color:transparent;color:#0a0a0a}.button.is-white.is-focused:not(:active),.button.is-white:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.button.is-white.is-active,.button.is-white:active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-hovered,.button.is-white.is-inverted:hover{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined.is-focused,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-outlined.is-loading.is-focused::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined.is-focused,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined:hover{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black.is-hovered,.button.is-black:hover{background-color:#040404;border-color:transparent;color:#fff}.button.is-black.is-focused,.button.is-black:focus{border-color:transparent;color:#fff}.button.is-black.is-focused:not(:active),.button.is-black:focus:not(:active){box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.button.is-black.is-active,.button.is-black:active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-hovered,.button.is-black.is-inverted:hover{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined.is-focused,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-outlined.is-loading.is-focused::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined.is-focused,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined:hover{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #0a0a0a #0a0a0a!important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-hovered,.button.is-light:hover{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused,.button.is-light:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light.is-focused:not(:active),.button.is-light:focus:not(:active){box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.button.is-light.is-active,.button.is-light:active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-hovered,.button.is-light.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined.is-focused,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-outlined.is-loading.is-focused::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-light.is-inverted.is-outlined.is-focused,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f5f5f5 #f5f5f5!important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-dark{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark.is-hovered,.button.is-dark:hover{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark.is-focused,.button.is-dark:focus{border-color:transparent;color:#fff}.button.is-dark.is-focused:not(:active),.button.is-dark:focus:not(:active){box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.button.is-dark.is-active,.button.is-dark:active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],fieldset[disabled] .button.is-dark{background-color:#363636;border-color:#363636;box-shadow:none}.button.is-dark.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-hovered,.button.is-dark.is-inverted:hover{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined.is-focused,.button.is-dark.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.button.is-dark.is-outlined:hover{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-outlined.is-loading.is-focused::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-dark.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined.is-focused,.button.is-dark.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined:hover{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #363636 #363636!important}.button.is-dark.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary{background-color:#00d1b2;border-color:transparent;color:#fff}.button.is-primary.is-hovered,.button.is-primary:hover{background-color:#00c4a7;border-color:transparent;color:#fff}.button.is-primary.is-focused,.button.is-primary:focus{border-color:transparent;color:#fff}.button.is-primary.is-focused:not(:active),.button.is-primary:focus:not(:active){box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.button.is-primary.is-active,.button.is-primary:active{background-color:#00b89c;border-color:transparent;color:#fff}.button.is-primary[disabled],fieldset[disabled] .button.is-primary{background-color:#00d1b2;border-color:#00d1b2;box-shadow:none}.button.is-primary.is-inverted{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-hovered,.button.is-primary.is-inverted:hover{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],fieldset[disabled] .button.is-primary.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#00d1b2}.button.is-primary.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;color:#00d1b2}.button.is-primary.is-outlined.is-focused,.button.is-primary.is-outlined.is-hovered,.button.is-primary.is-outlined:focus,.button.is-primary.is-outlined:hover{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.button.is-primary.is-outlined.is-loading::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-outlined.is-loading.is-focused::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-outlined.is-loading:focus::after,.button.is-primary.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-primary.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-outlined{background-color:transparent;border-color:#00d1b2;box-shadow:none;color:#00d1b2}.button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined.is-focused,.button.is-primary.is-inverted.is-outlined.is-hovered,.button.is-primary.is-inverted.is-outlined:focus,.button.is-primary.is-inverted.is-outlined:hover{background-color:#fff;color:#00d1b2}.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #00d1b2 #00d1b2!important}.button.is-primary.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light{background-color:#ebfffc;color:#00947e}.button.is-primary.is-light.is-hovered,.button.is-primary.is-light:hover{background-color:#defffa;border-color:transparent;color:#00947e}.button.is-primary.is-light.is-active,.button.is-primary.is-light:active{background-color:#d1fff8;border-color:transparent;color:#00947e}.button.is-link{background-color:#485fc7;border-color:transparent;color:#fff}.button.is-link.is-hovered,.button.is-link:hover{background-color:#3e56c4;border-color:transparent;color:#fff}.button.is-link.is-focused,.button.is-link:focus{border-color:transparent;color:#fff}.button.is-link.is-focused:not(:active),.button.is-link:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.button.is-link.is-active,.button.is-link:active{background-color:#3a51bb;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#485fc7;border-color:#485fc7;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-hovered,.button.is-link.is-inverted:hover{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#485fc7}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;color:#485fc7}.button.is-link.is-outlined.is-focused,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined:hover{background-color:#485fc7;border-color:#485fc7;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-outlined.is-loading.is-focused::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#485fc7;box-shadow:none;color:#485fc7}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined.is-focused,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined:hover{background-color:#fff;color:#485fc7}.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #485fc7 #485fc7!important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff1fa;color:#3850b7}.button.is-link.is-light.is-hovered,.button.is-link.is-light:hover{background-color:#e6e9f7;border-color:transparent;color:#3850b7}.button.is-link.is-light.is-active,.button.is-link.is-light:active{background-color:#dce0f4;border-color:transparent;color:#3850b7}.button.is-info{background-color:#3e8ed0;border-color:transparent;color:#fff}.button.is-info.is-hovered,.button.is-info:hover{background-color:#3488ce;border-color:transparent;color:#fff}.button.is-info.is-focused,.button.is-info:focus{border-color:transparent;color:#fff}.button.is-info.is-focused:not(:active),.button.is-info:focus:not(:active){box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.button.is-info.is-active,.button.is-info:active{background-color:#3082c5;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#3e8ed0;border-color:#3e8ed0;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-hovered,.button.is-info.is-inverted:hover{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#3e8ed0}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;color:#3e8ed0}.button.is-info.is-outlined.is-focused,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined:hover{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-outlined.is-loading.is-focused::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#3e8ed0;box-shadow:none;color:#3e8ed0}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined.is-focused,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined:hover{background-color:#fff;color:#3e8ed0}.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #3e8ed0 #3e8ed0!important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#eff5fb;color:#296fa8}.button.is-info.is-light.is-hovered,.button.is-info.is-light:hover{background-color:#e4eff9;border-color:transparent;color:#296fa8}.button.is-info.is-light.is-active,.button.is-info.is-light:active{background-color:#dae9f6;border-color:transparent;color:#296fa8}.button.is-success{background-color:#48c78e;border-color:transparent;color:#fff}.button.is-success.is-hovered,.button.is-success:hover{background-color:#3ec487;border-color:transparent;color:#fff}.button.is-success.is-focused,.button.is-success:focus{border-color:transparent;color:#fff}.button.is-success.is-focused:not(:active),.button.is-success:focus:not(:active){box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.button.is-success.is-active,.button.is-success:active{background-color:#3abb81;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#48c78e;border-color:#48c78e;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-hovered,.button.is-success.is-inverted:hover{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#48c78e}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;color:#48c78e}.button.is-success.is-outlined.is-focused,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined:hover{background-color:#48c78e;border-color:#48c78e;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-outlined.is-loading.is-focused::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#48c78e;box-shadow:none;color:#48c78e}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined.is-focused,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined:hover{background-color:#fff;color:#48c78e}.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #48c78e #48c78e!important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#effaf5;color:#257953}.button.is-success.is-light.is-hovered,.button.is-success.is-light:hover{background-color:#e6f7ef;border-color:transparent;color:#257953}.button.is-success.is-light.is-active,.button.is-success.is-light:active{background-color:#dcf4e9;border-color:transparent;color:#257953}.button.is-warning{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-hovered,.button.is-warning:hover{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused,.button.is-warning:focus{border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning.is-focused:not(:active),.button.is-warning:focus:not(:active){box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.button.is-warning.is-active,.button.is-warning:active{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffe08a;border-color:#ffe08a;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-hovered,.button.is-warning.is-inverted:hover{background-color:rgba(0,0,0,.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,.7);border-color:transparent;box-shadow:none;color:#ffe08a}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;color:#ffe08a}.button.is-warning.is-outlined.is-focused,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined:hover{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-outlined.is-loading.is-focused::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading:hover::after{border-color:transparent transparent rgba(0,0,0,.7) rgba(0,0,0,.7)!important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffe08a;box-shadow:none;color:#ffe08a}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);color:rgba(0,0,0,.7)}.button.is-warning.is-inverted.is-outlined.is-focused,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined:hover{background-color:rgba(0,0,0,.7);color:#ffe08a}.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #ffe08a #ffe08a!important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,.7);box-shadow:none;color:rgba(0,0,0,.7)}.button.is-warning.is-light{background-color:#fffaeb;color:#946c00}.button.is-warning.is-light.is-hovered,.button.is-warning.is-light:hover{background-color:#fff6de;border-color:transparent;color:#946c00}.button.is-warning.is-light.is-active,.button.is-warning.is-light:active{background-color:#fff3d1;border-color:transparent;color:#946c00}.button.is-danger{background-color:#f14668;border-color:transparent;color:#fff}.button.is-danger.is-hovered,.button.is-danger:hover{background-color:#f03a5f;border-color:transparent;color:#fff}.button.is-danger.is-focused,.button.is-danger:focus{border-color:transparent;color:#fff}.button.is-danger.is-focused:not(:active),.button.is-danger:focus:not(:active){box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.button.is-danger.is-active,.button.is-danger:active{background-color:#ef2e55;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#f14668;border-color:#f14668;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-hovered,.button.is-danger.is-inverted:hover{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#f14668}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;color:#f14668}.button.is-danger.is-outlined.is-focused,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined:hover{background-color:#f14668;border-color:#f14668;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-outlined.is-loading.is-focused::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading:hover::after{border-color:transparent transparent #fff #fff!important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#f14668;box-shadow:none;color:#f14668}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined.is-focused,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined:hover{background-color:#fff;color:#f14668}.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading:hover::after{border-color:transparent transparent #f14668 #f14668!important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.button.is-danger.is-light.is-hovered,.button.is-danger.is-light:hover{background-color:#fde0e6;border-color:transparent;color:#cc0f35}.button.is-danger.is-light.is-active,.button.is-danger.is-light:active{background-color:#fcd4dc;border-color:transparent;color:#cc0f35}.button.is-small{font-size:.75rem}.button.is-small:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent!important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * .5));top:calc(50% - (1em * .5));position:absolute!important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#7a7a7a;box-shadow:none;pointer-events:none}.button.is-rounded{border-radius:9999px;padding-left:calc(1em + .25em);padding-right:calc(1em + .25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}.buttons:last-child{margin-bottom:-.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button.is-hovered,.buttons.has-addons .button:hover{z-index:2}.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-focused,.buttons.has-addons .button.is-selected,.buttons.has-addons .button:active,.buttons.has-addons .button:focus{z-index:3}.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button.is-selected:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button:focus:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:.25rem;margin-right:.25rem}@media screen and (max-width:768px){.button.is-responsive.is-small{font-size:.5625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.65625rem}.button.is-responsive.is-medium{font-size:.75rem}.button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.button.is-responsive.is-small{font-size:.65625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.75rem}.button.is-responsive.is-medium{font-size:1rem}.button.is-responsive.is-large{font-size:1.25rem}}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none!important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width:1024px){.container{max-width:960px}}@media screen and (max-width:1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width:1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width:1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width:1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:.25em}.content blockquote:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content p:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child),.content ul:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#363636;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:.8em}.content h5{font-size:1.125em;margin-bottom:.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sub,.content sup{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.content table th{color:#363636}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#363636}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#363636}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:9999px}.image.is-fullwidth{width:100%}.image.is-16by9 .has-ratio,.image.is-16by9 img,.image.is-1by1 .has-ratio,.image.is-1by1 img,.image.is-1by2 .has-ratio,.image.is-1by2 img,.image.is-1by3 .has-ratio,.image.is-1by3 img,.image.is-2by1 .has-ratio,.image.is-2by1 img,.image.is-2by3 .has-ratio,.image.is-2by3 img,.image.is-3by1 .has-ratio,.image.is-3by1 img,.image.is-3by2 .has-ratio,.image.is-3by2 img,.image.is-3by4 .has-ratio,.image.is-3by4 img,.image.is-3by5 .has-ratio,.image.is-3by5 img,.image.is-4by3 .has-ratio,.image.is-4by3 img,.image.is-4by5 .has-ratio,.image.is-4by5 img,.image.is-5by3 .has-ratio,.image.is-5by3 img,.image.is-5by4 .has-ratio,.image.is-5by4 img,.image.is-9by16 .has-ratio,.image.is-9by16 img,.image.is-square .has-ratio,.image.is-square img{height:100%;width:100%}.image.is-1by1,.image.is-square{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:0 0}.notification>.delete{right:.5rem;position:absolute;top:.5rem}.notification .content,.notification .subtitle,.notification .title{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.notification.is-dark{background-color:#363636;color:#fff}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-primary.is-light{background-color:#ebfffc;color:#00947e}.notification.is-link{background-color:#485fc7;color:#fff}.notification.is-link.is-light{background-color:#eff1fa;color:#3850b7}.notification.is-info{background-color:#3e8ed0;color:#fff}.notification.is-info.is-light{background-color:#eff5fb;color:#296fa8}.notification.is-success{background-color:#48c78e;color:#fff}.notification.is-success.is-light{background-color:#effaf5;color:#257953}.notification.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.notification.is-warning.is-light{background-color:#fffaeb;color:#946c00}.notification.is-danger{background-color:#f14668;color:#fff}.notification.is-danger.is-light{background-color:#feecf0;color:#cc0f35}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right,#fff 30%,#ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right,#0a0a0a 30%,#ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right,#f5f5f5 30%,#ededed 30%)}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate{background-image:linear-gradient(to right,#363636 30%,#ededed 30%)}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-primary:indeterminate{background-image:linear-gradient(to right,#00d1b2 30%,#ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#485fc7}.progress.is-link::-moz-progress-bar{background-color:#485fc7}.progress.is-link::-ms-fill{background-color:#485fc7}.progress.is-link:indeterminate{background-image:linear-gradient(to right,#485fc7 30%,#ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#3e8ed0}.progress.is-info::-moz-progress-bar{background-color:#3e8ed0}.progress.is-info::-ms-fill{background-color:#3e8ed0}.progress.is-info:indeterminate{background-image:linear-gradient(to right,#3e8ed0 30%,#ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#48c78e}.progress.is-success::-moz-progress-bar{background-color:#48c78e}.progress.is-success::-ms-fill{background-color:#48c78e}.progress.is-success:indeterminate{background-image:linear-gradient(to right,#48c78e 30%,#ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffe08a}.progress.is-warning::-moz-progress-bar{background-color:#ffe08a}.progress.is-warning::-ms-fill{background-color:#ffe08a}.progress.is-warning:indeterminate{background-image:linear-gradient(to right,#ffe08a 30%,#ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#f14668}.progress.is-danger::-moz-progress-bar{background-color:#f14668}.progress.is-danger::-ms-fill{background-color:#f14668}.progress.is-danger:indeterminate{background-image:linear-gradient(to right,#f14668 30%,#ededed 30%)}.progress:indeterminate{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:moveIndeterminate;animation-name:moveIndeterminate;-webkit-animation-timing-function:linear;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right,#4a4a4a 30%,#ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@-webkit-keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:.5em .75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#485fc7;border-color:#485fc7;color:#fff}.table td.is-info,.table th.is-info{background-color:#3e8ed0;border-color:#3e8ed0;color:#fff}.table td.is-success,.table th.is-success{background-color:#48c78e;border-color:#48c78e;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffe08a;border-color:#ffe08a;color:rgba(0,0,0,.7)}.table td.is-danger,.table th.is-danger{background-color:#f14668;border-color:#f14668;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#363636}.table th:not([align]){text-align:left}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:transparent}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot{background-color:transparent}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody{background-color:transparent}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(2n){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:.25em .5em}.table.is-striped tbody tr:not(.is-selected):nth-child(2n){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:.5rem}.tags .tag:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:.25rem;margin-left:.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.tags.has-addons .tag:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:.75em;padding-right:.75em;white-space:nowrap}.tag:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.tag:not(body).is-dark{background-color:#363636;color:#fff}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-primary.is-light{background-color:#ebfffc;color:#00947e}.tag:not(body).is-link{background-color:#485fc7;color:#fff}.tag:not(body).is-link.is-light{background-color:#eff1fa;color:#3850b7}.tag:not(body).is-info{background-color:#3e8ed0;color:#fff}.tag:not(body).is-info.is-light{background-color:#eff5fb;color:#296fa8}.tag:not(body).is-success{background-color:#48c78e;color:#fff}.tag:not(body).is-success.is-light{background-color:#effaf5;color:#257953}.tag:not(body).is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.tag:not(body).is-warning.is-light{background-color:#fffaeb;color:#946c00}.tag:not(body).is-danger{background-color:#f14668;color:#fff}.tag:not(body).is-danger.is-light{background-color:#feecf0;color:#cc0f35}.tag:not(body).is-normal{font-size:.75rem}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag:not(body).is-delete{margin-left:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::after,.tag:not(body).is-delete::before{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:focus,.tag:not(body).is-delete:hover{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:9999px}a.tag:hover{text-decoration:underline}.subtitle,.title{word-break:break-word}.subtitle em,.subtitle span,.title em,.title span{font-weight:inherit}.subtitle sub,.title sub{font-size:.75em}.subtitle sup,.title sup{font-size:.75em}.subtitle .tag,.title .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:.25rem .5rem;text-align:center;vertical-align:top}.input,.select select,.textarea{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#363636}.input::-moz-placeholder,.select select::-moz-placeholder,.textarea::-moz-placeholder{color:rgba(54,54,54,.3)}.input::-webkit-input-placeholder,.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:rgba(54,54,54,.3)}.input:-moz-placeholder,.select select:-moz-placeholder,.textarea:-moz-placeholder{color:rgba(54,54,54,.3)}.input:-ms-input-placeholder,.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:rgba(54,54,54,.3)}.input:hover,.is-hovered.input,.is-hovered.textarea,.select select.is-hovered,.select select:hover,.textarea:hover{border-color:#b5b5b5}.input:active,.input:focus,.is-active.input,.is-active.textarea,.is-focused.input,.is-focused.textarea,.select select.is-active,.select select.is-focused,.select select:active,.select select:focus,.textarea:active,.textarea:focus{border-color:#485fc7;box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.input[disabled],.select fieldset[disabled] select,.select select[disabled],.textarea[disabled],fieldset[disabled] .input,fieldset[disabled] .select select,fieldset[disabled] .textarea{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#7a7a7a}.input[disabled]::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder{color:rgba(122,122,122,.3)}.input[disabled]:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder{color:rgba(122,122,122,.3)}.input,.textarea{box-shadow:inset 0 .0625em .125em rgba(10,10,10,.05);max-width:100%;width:100%}.input[readonly],.textarea[readonly]{box-shadow:none}.is-white.input,.is-white.textarea{border-color:#fff}.is-white.input:active,.is-white.input:focus,.is-white.is-active.input,.is-white.is-active.textarea,.is-white.is-focused.input,.is-white.is-focused.textarea,.is-white.textarea:active,.is-white.textarea:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.is-black.input,.is-black.textarea{border-color:#0a0a0a}.is-black.input:active,.is-black.input:focus,.is-black.is-active.input,.is-black.is-active.textarea,.is-black.is-focused.input,.is-black.is-focused.textarea,.is-black.textarea:active,.is-black.textarea:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.is-light.input,.is-light.textarea{border-color:#f5f5f5}.is-light.input:active,.is-light.input:focus,.is-light.is-active.input,.is-light.is-active.textarea,.is-light.is-focused.input,.is-light.is-focused.textarea,.is-light.textarea:active,.is-light.textarea:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.is-dark.input,.is-dark.textarea{border-color:#363636}.is-dark.input:active,.is-dark.input:focus,.is-dark.is-active.input,.is-dark.is-active.textarea,.is-dark.is-focused.input,.is-dark.is-focused.textarea,.is-dark.textarea:active,.is-dark.textarea:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.is-primary.input,.is-primary.textarea{border-color:#00d1b2}.is-primary.input:active,.is-primary.input:focus,.is-primary.is-active.input,.is-primary.is-active.textarea,.is-primary.is-focused.input,.is-primary.is-focused.textarea,.is-primary.textarea:active,.is-primary.textarea:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.is-link.input,.is-link.textarea{border-color:#485fc7}.is-link.input:active,.is-link.input:focus,.is-link.is-active.input,.is-link.is-active.textarea,.is-link.is-focused.input,.is-link.is-focused.textarea,.is-link.textarea:active,.is-link.textarea:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.is-info.input,.is-info.textarea{border-color:#3e8ed0}.is-info.input:active,.is-info.input:focus,.is-info.is-active.input,.is-info.is-active.textarea,.is-info.is-focused.input,.is-info.is-focused.textarea,.is-info.textarea:active,.is-info.textarea:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.is-success.input,.is-success.textarea{border-color:#48c78e}.is-success.input:active,.is-success.input:focus,.is-success.is-active.input,.is-success.is-active.textarea,.is-success.is-focused.input,.is-success.is-focused.textarea,.is-success.textarea:active,.is-success.textarea:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.is-warning.input,.is-warning.textarea{border-color:#ffe08a}.is-warning.input:active,.is-warning.input:focus,.is-warning.is-active.input,.is-warning.is-active.textarea,.is-warning.is-focused.input,.is-warning.is-focused.textarea,.is-warning.textarea:active,.is-warning.textarea:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.is-danger.input,.is-danger.textarea{border-color:#f14668}.is-danger.input:active,.is-danger.input:focus,.is-danger.is-active.input,.is-danger.is-active.textarea,.is-danger.is-focused.input,.is-danger.is-focused.textarea,.is-danger.textarea:active,.is-danger.textarea:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.is-small.input,.is-small.textarea{border-radius:2px;font-size:.75rem}.is-medium.input,.is-medium.textarea{font-size:1.25rem}.is-large.input,.is-large.textarea{font-size:1.5rem}.is-fullwidth.input,.is-fullwidth.textarea{display:block;width:100%}.is-inline.input,.is-inline.textarea{display:inline;width:auto}.input.is-rounded{border-radius:9999px;padding-left:calc(calc(.75em - 1px) + .375em);padding-right:calc(calc(.75em - 1px) + .375em)}.input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.checkbox,.radio{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.checkbox input,.radio input{cursor:pointer}.checkbox:hover,.radio:hover{color:#363636}.checkbox input[disabled],.checkbox[disabled],.radio input[disabled],.radio[disabled],fieldset[disabled] .checkbox,fieldset[disabled] .radio{color:#7a7a7a;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#485fc7;right:1.125em;z-index:4}.select.is-rounded select{border-radius:9999px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:0}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#363636}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select.is-hovered,.select.is-white select:hover{border-color:#f2f2f2}.select.is-white select.is-active,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select:focus{box-shadow:0 0 0 .125em rgba(255,255,255,.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select.is-hovered,.select.is-black select:hover{border-color:#000}.select.is-black select.is-active,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select:focus{box-shadow:0 0 0 .125em rgba(10,10,10,.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select.is-hovered,.select.is-light select:hover{border-color:#e8e8e8}.select.is-light select.is-active,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select:focus{box-shadow:0 0 0 .125em rgba(245,245,245,.25)}.select.is-dark:not(:hover)::after{border-color:#363636}.select.is-dark select{border-color:#363636}.select.is-dark select.is-hovered,.select.is-dark select:hover{border-color:#292929}.select.is-dark select.is-active,.select.is-dark select.is-focused,.select.is-dark select:active,.select.is-dark select:focus{box-shadow:0 0 0 .125em rgba(54,54,54,.25)}.select.is-primary:not(:hover)::after{border-color:#00d1b2}.select.is-primary select{border-color:#00d1b2}.select.is-primary select.is-hovered,.select.is-primary select:hover{border-color:#00b89c}.select.is-primary select.is-active,.select.is-primary select.is-focused,.select.is-primary select:active,.select.is-primary select:focus{box-shadow:0 0 0 .125em rgba(0,209,178,.25)}.select.is-link:not(:hover)::after{border-color:#485fc7}.select.is-link select{border-color:#485fc7}.select.is-link select.is-hovered,.select.is-link select:hover{border-color:#3a51bb}.select.is-link select.is-active,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select:focus{box-shadow:0 0 0 .125em rgba(72,95,199,.25)}.select.is-info:not(:hover)::after{border-color:#3e8ed0}.select.is-info select{border-color:#3e8ed0}.select.is-info select.is-hovered,.select.is-info select:hover{border-color:#3082c5}.select.is-info select.is-active,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select:focus{box-shadow:0 0 0 .125em rgba(62,142,208,.25)}.select.is-success:not(:hover)::after{border-color:#48c78e}.select.is-success select{border-color:#48c78e}.select.is-success select.is-hovered,.select.is-success select:hover{border-color:#3abb81}.select.is-success select.is-active,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select:focus{box-shadow:0 0 0 .125em rgba(72,199,142,.25)}.select.is-warning:not(:hover)::after{border-color:#ffe08a}.select.is-warning select{border-color:#ffe08a}.select.is-warning select.is-hovered,.select.is-warning select:hover{border-color:#ffd970}.select.is-warning select.is-active,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select:focus{box-shadow:0 0 0 .125em rgba(255,224,138,.25)}.select.is-danger:not(:hover)::after{border-color:#f14668}.select.is-danger select{border-color:#f14668}.select.is-danger select.is-hovered,.select.is-danger select:hover{border-color:#ef2e55}.select.is-danger select.is-active,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select:focus{box-shadow:0 0 0 .125em rgba(241,70,104,.25)}.select.is-small{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#7a7a7a!important;opacity:.5}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:.625em;transform:none}.select.is-loading.is-small:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white.is-hovered .file-cta,.file.is-white:hover .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white.is-focused .file-cta,.file.is-white:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,255,255,.25);color:#0a0a0a}.file.is-white.is-active .file-cta,.file.is-white:active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black.is-hovered .file-cta,.file.is-black:hover .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black.is-focused .file-cta,.file.is-black:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(10,10,10,.25);color:#fff}.file.is-black.is-active .file-cta,.file.is-black:active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-hovered .file-cta,.file.is-light:hover .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-light.is-focused .file-cta,.file.is-light:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(245,245,245,.25);color:rgba(0,0,0,.7)}.file.is-light.is-active .file-cta,.file.is-light:active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-dark .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark.is-hovered .file-cta,.file.is-dark:hover .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark.is-focused .file-cta,.file.is-dark:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(54,54,54,.25);color:#fff}.file.is-dark.is-active .file-cta,.file.is-dark:active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta{background-color:#00d1b2;border-color:transparent;color:#fff}.file.is-primary.is-hovered .file-cta,.file.is-primary:hover .file-cta{background-color:#00c4a7;border-color:transparent;color:#fff}.file.is-primary.is-focused .file-cta,.file.is-primary:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(0,209,178,.25);color:#fff}.file.is-primary.is-active .file-cta,.file.is-primary:active .file-cta{background-color:#00b89c;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#485fc7;border-color:transparent;color:#fff}.file.is-link.is-hovered .file-cta,.file.is-link:hover .file-cta{background-color:#3e56c4;border-color:transparent;color:#fff}.file.is-link.is-focused .file-cta,.file.is-link:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,95,199,.25);color:#fff}.file.is-link.is-active .file-cta,.file.is-link:active .file-cta{background-color:#3a51bb;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#3e8ed0;border-color:transparent;color:#fff}.file.is-info.is-hovered .file-cta,.file.is-info:hover .file-cta{background-color:#3488ce;border-color:transparent;color:#fff}.file.is-info.is-focused .file-cta,.file.is-info:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(62,142,208,.25);color:#fff}.file.is-info.is-active .file-cta,.file.is-info:active .file-cta{background-color:#3082c5;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#48c78e;border-color:transparent;color:#fff}.file.is-success.is-hovered .file-cta,.file.is-success:hover .file-cta{background-color:#3ec487;border-color:transparent;color:#fff}.file.is-success.is-focused .file-cta,.file.is-success:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(72,199,142,.25);color:#fff}.file.is-success.is-active .file-cta,.file.is-success:active .file-cta{background-color:#3abb81;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffe08a;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-hovered .file-cta,.file.is-warning:hover .file-cta{background-color:#ffdc7d;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-warning.is-focused .file-cta,.file.is-warning:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(255,224,138,.25);color:rgba(0,0,0,.7)}.file.is-warning.is-active .file-cta,.file.is-warning:active .file-cta{background-color:#ffd970;border-color:transparent;color:rgba(0,0,0,.7)}.file.is-danger .file-cta{background-color:#f14668;border-color:transparent;color:#fff}.file.is-danger.is-hovered .file-cta,.file.is-danger:hover .file-cta{background-color:#f03a5f;border-color:transparent;color:#fff}.file.is-danger.is-focused .file-cta,.file.is-danger:focus .file-cta{border-color:transparent;box-shadow:0 0 .5em rgba(241,70,104,.25);color:#fff}.file.is-danger.is-active .file-cta,.file.is-danger:active .file-cta{background-color:#ef2e55;border-color:transparent;color:#fff}.file.is-small{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#363636}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#363636}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:0;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#4a4a4a}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#363636;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:.5em}.label.is-small{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark{color:#363636}.help.is-primary{color:#00d1b2}.help.is-link{color:#485fc7}.help.is-info{color:#3e8ed0}.help.is-success{color:#48c78e}.help.is-warning{color:#ffe08a}.help.is-danger{color:#f14668}.field:not(:last-child){margin-bottom:.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]).is-hovered,.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .input:not([disabled]).is-hovered,.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]).is-hovered,.field.has-addons .control .select select:not([disabled]):hover{z-index:2}.field.has-addons .control .button:not([disabled]).is-active,.field.has-addons .control .button:not([disabled]).is-focused,.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .input:not([disabled]).is-active,.field.has-addons .control .input:not([disabled]).is-focused,.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control .select select:not([disabled]).is-active,.field.has-addons .control .select select:not([disabled]).is-focused,.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select:not([disabled]):focus{z-index:3}.field.has-addons .control .button:not([disabled]).is-active:hover,.field.has-addons .control .button:not([disabled]).is-focused:hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .input:not([disabled]).is-active:hover,.field.has-addons .control .input:not([disabled]).is-focused:hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control .select select:not([disabled]).is-active:hover,.field.has-addons .control .select select:not([disabled]).is-focused:hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select:not([disabled]):focus:hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width:769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width:768px){.field-label{margin-bottom:.5rem}}@media screen and (min-width:769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:.375em}.field-label.is-normal{padding-top:.375em}.field-label.is-medium{font-size:1.25rem;padding-top:.375em}.field-label.is-large{font-size:1.5rem;padding-top:.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width:769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#4a4a4a}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute!important;right:.625em;top:.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#485fc7;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ol,.breadcrumb ul{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);color:#4a4a4a;max-width:100%;position:relative}.card-content:first-child,.card-footer:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-content:last-child,.card-footer:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:transparent;align-items:stretch;box-shadow:0 .125em .25em rgba(10,10,10,.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:transparent;padding:1.5rem}.card-footer{background-color:transparent;border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:.875rem;line-height:1.5;padding:.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#485fc7;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width:769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .subtitle,.level-item .title{margin-bottom:0}@media screen and (max-width:768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width:769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width:768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width:769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width:769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width:768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:.5em .75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#485fc7;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#7a7a7a;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body{border-color:#363636}.message.is-primary{background-color:#ebfffc}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#00947e}.message.is-link{background-color:#eff1fa}.message.is-link .message-header{background-color:#485fc7;color:#fff}.message.is-link .message-body{border-color:#485fc7;color:#3850b7}.message.is-info{background-color:#eff5fb}.message.is-info .message-header{background-color:#3e8ed0;color:#fff}.message.is-info .message-body{border-color:#3e8ed0;color:#296fa8}.message.is-success{background-color:#effaf5}.message.is-success .message-header{background-color:#48c78e;color:#fff}.message.is-success .message-body{border-color:#48c78e;color:#257953}.message.is-warning{background-color:#fffaeb}.message.is-warning .message-header{background-color:#ffe08a;color:rgba(0,0,0,.7)}.message.is-warning .message-body{border-color:#ffe08a;color:#946c00}.message.is-danger{background-color:#feecf0}.message.is-danger .message-header{background-color:#f14668;color:#fff}.message.is-danger .message-body{border-color:#f14668;color:#cc0f35}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:transparent}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,.86)}.modal-card,.modal-content{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width:769px){.modal-card,.modal-content{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:0 0;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-foot,.modal-card-head{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link,.navbar.is-white .navbar-brand>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width:1024px){.navbar.is-white .navbar-end .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-start>.navbar-item{color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-end .navbar-link::after,.navbar.is-white .navbar-start .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand .navbar-link,.navbar.is-black .navbar-brand>.navbar-item{color:#fff}.navbar.is-black .navbar-brand .navbar-link.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-black .navbar-end .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-start>.navbar-item{color:#fff}.navbar.is-black .navbar-end .navbar-link.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover{background-color:#000;color:#fff}.navbar.is-black .navbar-end .navbar-link::after,.navbar.is-black .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link,.navbar.is-light .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-light .navbar-end .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-end .navbar-link::after,.navbar.is-light .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,.7)}}.navbar.is-dark{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand .navbar-link,.navbar.is-dark .navbar-brand>.navbar-item{color:#fff}.navbar.is-dark .navbar-brand .navbar-link.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-dark .navbar-end .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-start>.navbar-item{color:#fff}.navbar.is-dark .navbar-end .navbar-link.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover{background-color:#292929;color:#fff}.navbar.is-dark .navbar-end .navbar-link::after,.navbar.is-dark .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand .navbar-link,.navbar.is-primary .navbar-brand>.navbar-item{color:#fff}.navbar.is-primary .navbar-brand .navbar-link.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-primary .navbar-end .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-start>.navbar-item{color:#fff}.navbar.is-primary .navbar-end .navbar-link.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-end .navbar-link::after,.navbar.is-primary .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#485fc7;color:#fff}.navbar.is-link .navbar-brand .navbar-link,.navbar.is-link .navbar-brand>.navbar-item{color:#fff}.navbar.is-link .navbar-brand .navbar-link.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-link .navbar-end .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-start>.navbar-item{color:#fff}.navbar.is-link .navbar-end .navbar-link.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-end .navbar-link::after,.navbar.is-link .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link{background-color:#3a51bb;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#485fc7;color:#fff}}.navbar.is-info{background-color:#3e8ed0;color:#fff}.navbar.is-info .navbar-brand .navbar-link,.navbar.is-info .navbar-brand>.navbar-item{color:#fff}.navbar.is-info .navbar-brand .navbar-link.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-info .navbar-end .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-start>.navbar-item{color:#fff}.navbar.is-info .navbar-end .navbar-link.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-end .navbar-link::after,.navbar.is-info .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link{background-color:#3082c5;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#3e8ed0;color:#fff}}.navbar.is-success{background-color:#48c78e;color:#fff}.navbar.is-success .navbar-brand .navbar-link,.navbar.is-success .navbar-brand>.navbar-item{color:#fff}.navbar.is-success .navbar-brand .navbar-link.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-success .navbar-end .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-start>.navbar-item{color:#fff}.navbar.is-success .navbar-end .navbar-link.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-end .navbar-link::after,.navbar.is-success .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link{background-color:#3abb81;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#48c78e;color:#fff}}.navbar.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link,.navbar.is-warning .navbar-brand>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,.7)}@media screen and (min-width:1024px){.navbar.is-warning .navbar-end .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-start>.navbar-item{color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-end .navbar-link::after,.navbar.is-warning .navbar-start .navbar-link::after{border-color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link{background-color:#ffd970;color:rgba(0,0,0,.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffe08a;color:rgba(0,0,0,.7)}}.navbar.is-danger{background-color:#f14668;color:#fff}.navbar.is-danger .navbar-brand .navbar-link,.navbar.is-danger .navbar-brand>.navbar-item{color:#fff}.navbar.is-danger .navbar-brand .navbar-link.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width:1024px){.navbar.is-danger .navbar-end .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-start>.navbar-item{color:#fff}.navbar.is-danger .navbar-end .navbar-link.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-end .navbar-link::after,.navbar.is-danger .navbar-start .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link{background-color:#ef2e55;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#f14668;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}body.has-navbar-fixed-top,html.has-navbar-fixed-top{padding-top:3.25rem}body.has-navbar-fixed-bottom,html.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:0 0;border:none;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color,opacity,transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:first-child{top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,.05)}.navbar-burger.is-active span:first-child{transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:.5rem .75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-.25rem;margin-right:-.25rem}.navbar-link,a.navbar-item{cursor:pointer}.navbar-link.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,a.navbar-item.is-active,a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover{background-color:#fafafa;color:#485fc7}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:transparent;border-bottom-color:#485fc7}.navbar-item.is-tab.is-active{background-color:transparent;border-bottom-color:#485fc7;border-bottom-style:solid;border-bottom-width:3px;color:#485fc7;padding-bottom:calc(.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#485fc7;margin-top:-.375em;right:1.125em}.navbar-dropdown{font-size:.875rem;padding-bottom:.5rem;padding-top:.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:.5rem 0}@media screen and (max-width:1023px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,.1);padding:.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}body.has-navbar-fixed-top-touch,html.has-navbar-fixed-top-touch{padding-top:3.25rem}body.has-navbar-fixed-bottom-touch,html.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width:1024px){.navbar,.navbar-end,.navbar-menu,.navbar-start{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-end,.navbar.is-spaced .navbar-start{align-items:center}.navbar.is-spaced .navbar-link,.navbar.is-spaced a.navbar-item{border-radius:4px}.navbar.is-transparent .navbar-link.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover{background-color:transparent!important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent!important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(.25em,-.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,.1);display:none;font-size:.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#485fc7}.navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-dropdown{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity,transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.container>.navbar .navbar-brand,.navbar>.container .navbar-brand{margin-left:-.75rem}.container>.navbar .navbar-menu,.navbar>.container .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,.1)}.navbar.is-fixed-top-desktop{top:0}body.has-navbar-fixed-top-desktop,html.has-navbar-fixed-top-desktop{padding-top:3.25rem}body.has-navbar-fixed-bottom-desktop,html.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}body.has-spaced-navbar-fixed-top,html.has-spaced-navbar-fixed-top{padding-top:5.25rem}body.has-spaced-navbar-fixed-bottom,html.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}.navbar-link.is-active,a.navbar-item.is-active{color:#0a0a0a}.navbar-link.is-active:not(:focus):not(:hover),a.navbar-item.is-active:not(:focus):not(:hover){background-color:transparent}.navbar-item.has-dropdown.is-active .navbar-link,.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-next,.pagination.is-rounded .pagination-previous{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-link,.pagination-next,.pagination-previous{border-color:#dbdbdb;color:#363636;min-width:2.5em}.pagination-link:hover,.pagination-next:hover,.pagination-previous:hover{border-color:#b5b5b5;color:#363636}.pagination-link:focus,.pagination-next:focus,.pagination-previous:focus{border-color:#485fc7}.pagination-link:active,.pagination-next:active,.pagination-previous:active{box-shadow:inset 0 1px 2px rgba(10,10,10,.2)}.pagination-link.is-disabled,.pagination-link[disabled],.pagination-next.is-disabled,.pagination-next[disabled],.pagination-previous.is-disabled,.pagination-previous[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:.5}.pagination-next,.pagination-previous{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#485fc7;border-color:#485fc7;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width:768px){.pagination{flex-wrap:wrap}.pagination-next,.pagination-previous{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width:769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-ellipsis,.pagination-link,.pagination-next,.pagination-previous{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:0 .5em 1em -.125em rgba(10,10,10,.1),0 0 0 1px rgba(10,10,10,.02);font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading{background-color:#00d1b2;color:#fff}.panel.is-primary .panel-tabs a.is-active{border-bottom-color:#00d1b2}.panel.is-primary .panel-block.is-active .panel-icon{color:#00d1b2}.panel.is-link .panel-heading{background-color:#485fc7;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#485fc7}.panel.is-link .panel-block.is-active .panel-icon{color:#485fc7}.panel.is-info .panel-heading{background-color:#3e8ed0;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#3e8ed0}.panel.is-info .panel-block.is-active .panel-icon{color:#3e8ed0}.panel.is-success .panel-heading{background-color:#48c78e;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#48c78e}.panel.is-success .panel-block.is-active .panel-icon{color:#48c78e}.panel.is-warning .panel-heading{background-color:#ffe08a;color:rgba(0,0,0,.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffe08a}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffe08a}.panel.is-danger .panel-heading{background-color:#f14668;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#f14668}.panel.is-danger .panel-block.is-active .panel-icon{color:#f14668}.panel-block:not(:last-child),.panel-tabs:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#363636;font-size:1.25em;font-weight:700;line-height:1.25;padding:.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#485fc7}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:.5em .75em}.panel-block input[type=checkbox]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#485fc7;color:#363636}.panel-block.is-active .panel-icon{color:#485fc7}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#485fc7;color:#485fc7}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:.75em;padding-right:.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:transparent!important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li.is-active a{background-color:#485fc7;border-color:#485fc7;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width:768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-left:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-left:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-left:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-left:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-left:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-left:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-left:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-left:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width:769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width:1023px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-left:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-left:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-left:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-left:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-left:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-left:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-left:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-left:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width:1024px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-left:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-left:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-left:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-left:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-left:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-left:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-left:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-left:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width:1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-left:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-left:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-left:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-left:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-left:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-left:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-left:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-left:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width:1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-left:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-left:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-left:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-left:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-left:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-left:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-left:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-left:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0!important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width:769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width:1024px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap:0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap:0rem}@media screen and (max-width:768px){.columns.is-variable.is-0-mobile{--columnGap:0rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-0-tablet{--columnGap:0rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-0-tablet-only{--columnGap:0rem}}@media screen and (max-width:1023px){.columns.is-variable.is-0-touch{--columnGap:0rem}}@media screen and (min-width:1024px){.columns.is-variable.is-0-desktop{--columnGap:0rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-0-desktop-only{--columnGap:0rem}}@media screen and (min-width:1216px){.columns.is-variable.is-0-widescreen{--columnGap:0rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-0-widescreen-only{--columnGap:0rem}}@media screen and (min-width:1408px){.columns.is-variable.is-0-fullhd{--columnGap:0rem}}.columns.is-variable.is-1{--columnGap:0.25rem}@media screen and (max-width:768px){.columns.is-variable.is-1-mobile{--columnGap:0.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-1-tablet{--columnGap:0.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-1-tablet-only{--columnGap:0.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-1-touch{--columnGap:0.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-1-desktop{--columnGap:0.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-1-desktop-only{--columnGap:0.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-1-widescreen{--columnGap:0.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-1-widescreen-only{--columnGap:0.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-1-fullhd{--columnGap:0.25rem}}.columns.is-variable.is-2{--columnGap:0.5rem}@media screen and (max-width:768px){.columns.is-variable.is-2-mobile{--columnGap:0.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-2-tablet{--columnGap:0.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-2-tablet-only{--columnGap:0.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-2-touch{--columnGap:0.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-2-desktop{--columnGap:0.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-2-desktop-only{--columnGap:0.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-2-widescreen{--columnGap:0.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-2-widescreen-only{--columnGap:0.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-2-fullhd{--columnGap:0.5rem}}.columns.is-variable.is-3{--columnGap:0.75rem}@media screen and (max-width:768px){.columns.is-variable.is-3-mobile{--columnGap:0.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-3-tablet{--columnGap:0.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-3-tablet-only{--columnGap:0.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-3-touch{--columnGap:0.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-3-desktop{--columnGap:0.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-3-desktop-only{--columnGap:0.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-3-widescreen{--columnGap:0.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-3-widescreen-only{--columnGap:0.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-3-fullhd{--columnGap:0.75rem}}.columns.is-variable.is-4{--columnGap:1rem}@media screen and (max-width:768px){.columns.is-variable.is-4-mobile{--columnGap:1rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-4-tablet{--columnGap:1rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-4-tablet-only{--columnGap:1rem}}@media screen and (max-width:1023px){.columns.is-variable.is-4-touch{--columnGap:1rem}}@media screen and (min-width:1024px){.columns.is-variable.is-4-desktop{--columnGap:1rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-4-desktop-only{--columnGap:1rem}}@media screen and (min-width:1216px){.columns.is-variable.is-4-widescreen{--columnGap:1rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-4-widescreen-only{--columnGap:1rem}}@media screen and (min-width:1408px){.columns.is-variable.is-4-fullhd{--columnGap:1rem}}.columns.is-variable.is-5{--columnGap:1.25rem}@media screen and (max-width:768px){.columns.is-variable.is-5-mobile{--columnGap:1.25rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-5-tablet{--columnGap:1.25rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-5-tablet-only{--columnGap:1.25rem}}@media screen and (max-width:1023px){.columns.is-variable.is-5-touch{--columnGap:1.25rem}}@media screen and (min-width:1024px){.columns.is-variable.is-5-desktop{--columnGap:1.25rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-5-desktop-only{--columnGap:1.25rem}}@media screen and (min-width:1216px){.columns.is-variable.is-5-widescreen{--columnGap:1.25rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-5-widescreen-only{--columnGap:1.25rem}}@media screen and (min-width:1408px){.columns.is-variable.is-5-fullhd{--columnGap:1.25rem}}.columns.is-variable.is-6{--columnGap:1.5rem}@media screen and (max-width:768px){.columns.is-variable.is-6-mobile{--columnGap:1.5rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-6-tablet{--columnGap:1.5rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-6-tablet-only{--columnGap:1.5rem}}@media screen and (max-width:1023px){.columns.is-variable.is-6-touch{--columnGap:1.5rem}}@media screen and (min-width:1024px){.columns.is-variable.is-6-desktop{--columnGap:1.5rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-6-desktop-only{--columnGap:1.5rem}}@media screen and (min-width:1216px){.columns.is-variable.is-6-widescreen{--columnGap:1.5rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-6-widescreen-only{--columnGap:1.5rem}}@media screen and (min-width:1408px){.columns.is-variable.is-6-fullhd{--columnGap:1.5rem}}.columns.is-variable.is-7{--columnGap:1.75rem}@media screen and (max-width:768px){.columns.is-variable.is-7-mobile{--columnGap:1.75rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-7-tablet{--columnGap:1.75rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-7-tablet-only{--columnGap:1.75rem}}@media screen and (max-width:1023px){.columns.is-variable.is-7-touch{--columnGap:1.75rem}}@media screen and (min-width:1024px){.columns.is-variable.is-7-desktop{--columnGap:1.75rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-7-desktop-only{--columnGap:1.75rem}}@media screen and (min-width:1216px){.columns.is-variable.is-7-widescreen{--columnGap:1.75rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-7-widescreen-only{--columnGap:1.75rem}}@media screen and (min-width:1408px){.columns.is-variable.is-7-fullhd{--columnGap:1.75rem}}.columns.is-variable.is-8{--columnGap:2rem}@media screen and (max-width:768px){.columns.is-variable.is-8-mobile{--columnGap:2rem}}@media screen and (min-width:769px),print{.columns.is-variable.is-8-tablet{--columnGap:2rem}}@media screen and (min-width:769px) and (max-width:1023px){.columns.is-variable.is-8-tablet-only{--columnGap:2rem}}@media screen and (max-width:1023px){.columns.is-variable.is-8-touch{--columnGap:2rem}}@media screen and (min-width:1024px){.columns.is-variable.is-8-desktop{--columnGap:2rem}}@media screen and (min-width:1024px) and (max-width:1215px){.columns.is-variable.is-8-desktop-only{--columnGap:2rem}}@media screen and (min-width:1216px){.columns.is-variable.is-8-widescreen{--columnGap:2rem}}@media screen and (min-width:1216px) and (max-width:1407px){.columns.is-variable.is-8-widescreen-only{--columnGap:2rem}}@media screen and (min-width:1408px){.columns.is-variable.is-8-fullhd{--columnGap:2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:-webkit-min-content;min-height:-moz-min-content;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0!important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem!important}@media screen and (min-width:769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.has-text-white{color:#fff!important}a.has-text-white:focus,a.has-text-white:hover{color:#e6e6e6!important}.has-background-white{background-color:#fff!important}.has-text-black{color:#0a0a0a!important}a.has-text-black:focus,a.has-text-black:hover{color:#000!important}.has-background-black{background-color:#0a0a0a!important}.has-text-light{color:#f5f5f5!important}a.has-text-light:focus,a.has-text-light:hover{color:#dbdbdb!important}.has-background-light{background-color:#f5f5f5!important}.has-text-dark{color:#363636!important}a.has-text-dark:focus,a.has-text-dark:hover{color:#1c1c1c!important}.has-background-dark{background-color:#363636!important}.has-text-primary{color:#00d1b2!important}a.has-text-primary:focus,a.has-text-primary:hover{color:#009e86!important}.has-background-primary{background-color:#00d1b2!important}.has-text-primary-light{color:#ebfffc!important}a.has-text-primary-light:focus,a.has-text-primary-light:hover{color:#b8fff4!important}.has-background-primary-light{background-color:#ebfffc!important}.has-text-primary-dark{color:#00947e!important}a.has-text-primary-dark:focus,a.has-text-primary-dark:hover{color:#00c7a9!important}.has-background-primary-dark{background-color:#00947e!important}.has-text-link{color:#485fc7!important}a.has-text-link:focus,a.has-text-link:hover{color:#3449a8!important}.has-background-link{background-color:#485fc7!important}.has-text-link-light{color:#eff1fa!important}a.has-text-link-light:focus,a.has-text-link-light:hover{color:#c8cfee!important}.has-background-link-light{background-color:#eff1fa!important}.has-text-link-dark{color:#3850b7!important}a.has-text-link-dark:focus,a.has-text-link-dark:hover{color:#576dcb!important}.has-background-link-dark{background-color:#3850b7!important}.has-text-info{color:#3e8ed0!important}a.has-text-info:focus,a.has-text-info:hover{color:#2b74b1!important}.has-background-info{background-color:#3e8ed0!important}.has-text-info-light{color:#eff5fb!important}a.has-text-info-light:focus,a.has-text-info-light:hover{color:#c6ddf1!important}.has-background-info-light{background-color:#eff5fb!important}.has-text-info-dark{color:#296fa8!important}a.has-text-info-dark:focus,a.has-text-info-dark:hover{color:#368ace!important}.has-background-info-dark{background-color:#296fa8!important}.has-text-success{color:#48c78e!important}a.has-text-success:focus,a.has-text-success:hover{color:#34a873!important}.has-background-success{background-color:#48c78e!important}.has-text-success-light{color:#effaf5!important}a.has-text-success-light:focus,a.has-text-success-light:hover{color:#c8eedd!important}.has-background-success-light{background-color:#effaf5!important}.has-text-success-dark{color:#257953!important}a.has-text-success-dark:focus,a.has-text-success-dark:hover{color:#31a06e!important}.has-background-success-dark{background-color:#257953!important}.has-text-warning{color:#ffe08a!important}a.has-text-warning:focus,a.has-text-warning:hover{color:#ffd257!important}.has-background-warning{background-color:#ffe08a!important}.has-text-warning-light{color:#fffaeb!important}a.has-text-warning-light:focus,a.has-text-warning-light:hover{color:#ffecb8!important}.has-background-warning-light{background-color:#fffaeb!important}.has-text-warning-dark{color:#946c00!important}a.has-text-warning-dark:focus,a.has-text-warning-dark:hover{color:#c79200!important}.has-background-warning-dark{background-color:#946c00!important}.has-text-danger{color:#f14668!important}a.has-text-danger:focus,a.has-text-danger:hover{color:#ee1742!important}.has-background-danger{background-color:#f14668!important}.has-text-danger-light{color:#feecf0!important}a.has-text-danger-light:focus,a.has-text-danger-light:hover{color:#fabdc9!important}.has-background-danger-light{background-color:#feecf0!important}.has-text-danger-dark{color:#cc0f35!important}a.has-text-danger-dark:focus,a.has-text-danger-dark:hover{color:#ee2049!important}.has-background-danger-dark{background-color:#cc0f35!important}.has-text-black-bis{color:#121212!important}.has-background-black-bis{background-color:#121212!important}.has-text-black-ter{color:#242424!important}.has-background-black-ter{background-color:#242424!important}.has-text-grey-darker{color:#363636!important}.has-background-grey-darker{background-color:#363636!important}.has-text-grey-dark{color:#4a4a4a!important}.has-background-grey-dark{background-color:#4a4a4a!important}.has-text-grey{color:#7a7a7a!important}.has-background-grey{background-color:#7a7a7a!important}.has-text-grey-light{color:#b5b5b5!important}.has-background-grey-light{background-color:#b5b5b5!important}.has-text-grey-lighter{color:#dbdbdb!important}.has-background-grey-lighter{background-color:#dbdbdb!important}.has-text-white-ter{color:#f5f5f5!important}.has-background-white-ter{background-color:#f5f5f5!important}.has-text-white-bis{color:#fafafa!important}.has-background-white-bis{background-color:#fafafa!important}.is-flex-direction-row{flex-direction:row!important}.is-flex-direction-row-reverse{flex-direction:row-reverse!important}.is-flex-direction-column{flex-direction:column!important}.is-flex-direction-column-reverse{flex-direction:column-reverse!important}.is-flex-wrap-nowrap{flex-wrap:nowrap!important}.is-flex-wrap-wrap{flex-wrap:wrap!important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse!important}.is-justify-content-flex-start{justify-content:flex-start!important}.is-justify-content-flex-end{justify-content:flex-end!important}.is-justify-content-center{justify-content:center!important}.is-justify-content-space-between{justify-content:space-between!important}.is-justify-content-space-around{justify-content:space-around!important}.is-justify-content-space-evenly{justify-content:space-evenly!important}.is-justify-content-start{justify-content:start!important}.is-justify-content-end{justify-content:end!important}.is-justify-content-left{justify-content:left!important}.is-justify-content-right{justify-content:right!important}.is-align-content-flex-start{align-content:flex-start!important}.is-align-content-flex-end{align-content:flex-end!important}.is-align-content-center{align-content:center!important}.is-align-content-space-between{align-content:space-between!important}.is-align-content-space-around{align-content:space-around!important}.is-align-content-space-evenly{align-content:space-evenly!important}.is-align-content-stretch{align-content:stretch!important}.is-align-content-start{align-content:start!important}.is-align-content-end{align-content:end!important}.is-align-content-baseline{align-content:baseline!important}.is-align-items-stretch{align-items:stretch!important}.is-align-items-flex-start{align-items:flex-start!important}.is-align-items-flex-end{align-items:flex-end!important}.is-align-items-center{align-items:center!important}.is-align-items-baseline{align-items:baseline!important}.is-align-items-start{align-items:start!important}.is-align-items-end{align-items:end!important}.is-align-items-self-start{align-items:self-start!important}.is-align-items-self-end{align-items:self-end!important}.is-align-self-auto{align-self:auto!important}.is-align-self-flex-start{align-self:flex-start!important}.is-align-self-flex-end{align-self:flex-end!important}.is-align-self-center{align-self:center!important}.is-align-self-baseline{align-self:baseline!important}.is-align-self-stretch{align-self:stretch!important}.is-flex-grow-0{flex-grow:0!important}.is-flex-grow-1{flex-grow:1!important}.is-flex-grow-2{flex-grow:2!important}.is-flex-grow-3{flex-grow:3!important}.is-flex-grow-4{flex-grow:4!important}.is-flex-grow-5{flex-grow:5!important}.is-flex-shrink-0{flex-shrink:0!important}.is-flex-shrink-1{flex-shrink:1!important}.is-flex-shrink-2{flex-shrink:2!important}.is-flex-shrink-3{flex-shrink:3!important}.is-flex-shrink-4{flex-shrink:4!important}.is-flex-shrink-5{flex-shrink:5!important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left!important}.is-pulled-right{float:right!important}.is-radiusless{border-radius:0!important}.is-shadowless{box-shadow:none!important}.is-clickable{cursor:pointer!important;pointer-events:all!important}.is-clipped{overflow:hidden!important}.is-relative{position:relative!important}.is-marginless{margin:0!important}.is-paddingless{padding:0!important}.m-0{margin:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin:.25rem!important}.mt-1{margin-top:.25rem!important}.mr-1{margin-right:.25rem!important}.mb-1{margin-bottom:.25rem!important}.ml-1{margin-left:.25rem!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.m-2{margin:.5rem!important}.mt-2{margin-top:.5rem!important}.mr-2{margin-right:.5rem!important}.mb-2{margin-bottom:.5rem!important}.ml-2{margin-left:.5rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.m-3{margin:.75rem!important}.mt-3{margin-top:.75rem!important}.mr-3{margin-right:.75rem!important}.mb-3{margin-bottom:.75rem!important}.ml-3{margin-left:.75rem!important}.mx-3{margin-left:.75rem!important;margin-right:.75rem!important}.my-3{margin-top:.75rem!important;margin-bottom:.75rem!important}.m-4{margin:1rem!important}.mt-4{margin-top:1rem!important}.mr-4{margin-right:1rem!important}.mb-4{margin-bottom:1rem!important}.ml-4{margin-left:1rem!important}.mx-4{margin-left:1rem!important;margin-right:1rem!important}.my-4{margin-top:1rem!important;margin-bottom:1rem!important}.m-5{margin:1.5rem!important}.mt-5{margin-top:1.5rem!important}.mr-5{margin-right:1.5rem!important}.mb-5{margin-bottom:1.5rem!important}.ml-5{margin-left:1.5rem!important}.mx-5{margin-left:1.5rem!important;margin-right:1.5rem!important}.my-5{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.m-6{margin:3rem!important}.mt-6{margin-top:3rem!important}.mr-6{margin-right:3rem!important}.mb-6{margin-bottom:3rem!important}.ml-6{margin-left:3rem!important}.mx-6{margin-left:3rem!important;margin-right:3rem!important}.my-6{margin-top:3rem!important;margin-bottom:3rem!important}.m-auto{margin:auto!important}.mt-auto{margin-top:auto!important}.mr-auto{margin-right:auto!important}.mb-auto{margin-bottom:auto!important}.ml-auto{margin-left:auto!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.p-0{padding:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding:.25rem!important}.pt-1{padding-top:.25rem!important}.pr-1{padding-right:.25rem!important}.pb-1{padding-bottom:.25rem!important}.pl-1{padding-left:.25rem!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.p-2{padding:.5rem!important}.pt-2{padding-top:.5rem!important}.pr-2{padding-right:.5rem!important}.pb-2{padding-bottom:.5rem!important}.pl-2{padding-left:.5rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.p-3{padding:.75rem!important}.pt-3{padding-top:.75rem!important}.pr-3{padding-right:.75rem!important}.pb-3{padding-bottom:.75rem!important}.pl-3{padding-left:.75rem!important}.px-3{padding-left:.75rem!important;padding-right:.75rem!important}.py-3{padding-top:.75rem!important;padding-bottom:.75rem!important}.p-4{padding:1rem!important}.pt-4{padding-top:1rem!important}.pr-4{padding-right:1rem!important}.pb-4{padding-bottom:1rem!important}.pl-4{padding-left:1rem!important}.px-4{padding-left:1rem!important;padding-right:1rem!important}.py-4{padding-top:1rem!important;padding-bottom:1rem!important}.p-5{padding:1.5rem!important}.pt-5{padding-top:1.5rem!important}.pr-5{padding-right:1.5rem!important}.pb-5{padding-bottom:1.5rem!important}.pl-5{padding-left:1.5rem!important}.px-5{padding-left:1.5rem!important;padding-right:1.5rem!important}.py-5{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.p-6{padding:3rem!important}.pt-6{padding-top:3rem!important}.pr-6{padding-right:3rem!important}.pb-6{padding-bottom:3rem!important}.pl-6{padding-left:3rem!important}.px-6{padding-left:3rem!important;padding-right:3rem!important}.py-6{padding-top:3rem!important;padding-bottom:3rem!important}.p-auto{padding:auto!important}.pt-auto{padding-top:auto!important}.pr-auto{padding-right:auto!important}.pb-auto{padding-bottom:auto!important}.pl-auto{padding-left:auto!important}.px-auto{padding-left:auto!important;padding-right:auto!important}.py-auto{padding-top:auto!important;padding-bottom:auto!important}.is-size-1{font-size:3rem!important}.is-size-2{font-size:2.5rem!important}.is-size-3{font-size:2rem!important}.is-size-4{font-size:1.5rem!important}.is-size-5{font-size:1.25rem!important}.is-size-6{font-size:1rem!important}.is-size-7{font-size:.75rem!important}@media screen and (max-width:768px){.is-size-1-mobile{font-size:3rem!important}.is-size-2-mobile{font-size:2.5rem!important}.is-size-3-mobile{font-size:2rem!important}.is-size-4-mobile{font-size:1.5rem!important}.is-size-5-mobile{font-size:1.25rem!important}.is-size-6-mobile{font-size:1rem!important}.is-size-7-mobile{font-size:.75rem!important}}@media screen and (min-width:769px),print{.is-size-1-tablet{font-size:3rem!important}.is-size-2-tablet{font-size:2.5rem!important}.is-size-3-tablet{font-size:2rem!important}.is-size-4-tablet{font-size:1.5rem!important}.is-size-5-tablet{font-size:1.25rem!important}.is-size-6-tablet{font-size:1rem!important}.is-size-7-tablet{font-size:.75rem!important}}@media screen and (max-width:1023px){.is-size-1-touch{font-size:3rem!important}.is-size-2-touch{font-size:2.5rem!important}.is-size-3-touch{font-size:2rem!important}.is-size-4-touch{font-size:1.5rem!important}.is-size-5-touch{font-size:1.25rem!important}.is-size-6-touch{font-size:1rem!important}.is-size-7-touch{font-size:.75rem!important}}@media screen and (min-width:1024px){.is-size-1-desktop{font-size:3rem!important}.is-size-2-desktop{font-size:2.5rem!important}.is-size-3-desktop{font-size:2rem!important}.is-size-4-desktop{font-size:1.5rem!important}.is-size-5-desktop{font-size:1.25rem!important}.is-size-6-desktop{font-size:1rem!important}.is-size-7-desktop{font-size:.75rem!important}}@media screen and (min-width:1216px){.is-size-1-widescreen{font-size:3rem!important}.is-size-2-widescreen{font-size:2.5rem!important}.is-size-3-widescreen{font-size:2rem!important}.is-size-4-widescreen{font-size:1.5rem!important}.is-size-5-widescreen{font-size:1.25rem!important}.is-size-6-widescreen{font-size:1rem!important}.is-size-7-widescreen{font-size:.75rem!important}}@media screen and (min-width:1408px){.is-size-1-fullhd{font-size:3rem!important}.is-size-2-fullhd{font-size:2.5rem!important}.is-size-3-fullhd{font-size:2rem!important}.is-size-4-fullhd{font-size:1.5rem!important}.is-size-5-fullhd{font-size:1.25rem!important}.is-size-6-fullhd{font-size:1rem!important}.is-size-7-fullhd{font-size:.75rem!important}}.has-text-centered{text-align:center!important}.has-text-justified{text-align:justify!important}.has-text-left{text-align:left!important}.has-text-right{text-align:right!important}@media screen and (max-width:768px){.has-text-centered-mobile{text-align:center!important}}@media screen and (min-width:769px),print{.has-text-centered-tablet{text-align:center!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-centered-tablet-only{text-align:center!important}}@media screen and (max-width:1023px){.has-text-centered-touch{text-align:center!important}}@media screen and (min-width:1024px){.has-text-centered-desktop{text-align:center!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-centered-desktop-only{text-align:center!important}}@media screen and (min-width:1216px){.has-text-centered-widescreen{text-align:center!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-centered-widescreen-only{text-align:center!important}}@media screen and (min-width:1408px){.has-text-centered-fullhd{text-align:center!important}}@media screen and (max-width:768px){.has-text-justified-mobile{text-align:justify!important}}@media screen and (min-width:769px),print{.has-text-justified-tablet{text-align:justify!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-justified-tablet-only{text-align:justify!important}}@media screen and (max-width:1023px){.has-text-justified-touch{text-align:justify!important}}@media screen and (min-width:1024px){.has-text-justified-desktop{text-align:justify!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-justified-desktop-only{text-align:justify!important}}@media screen and (min-width:1216px){.has-text-justified-widescreen{text-align:justify!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-justified-widescreen-only{text-align:justify!important}}@media screen and (min-width:1408px){.has-text-justified-fullhd{text-align:justify!important}}@media screen and (max-width:768px){.has-text-left-mobile{text-align:left!important}}@media screen and (min-width:769px),print{.has-text-left-tablet{text-align:left!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-left-tablet-only{text-align:left!important}}@media screen and (max-width:1023px){.has-text-left-touch{text-align:left!important}}@media screen and (min-width:1024px){.has-text-left-desktop{text-align:left!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-left-desktop-only{text-align:left!important}}@media screen and (min-width:1216px){.has-text-left-widescreen{text-align:left!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-left-widescreen-only{text-align:left!important}}@media screen and (min-width:1408px){.has-text-left-fullhd{text-align:left!important}}@media screen and (max-width:768px){.has-text-right-mobile{text-align:right!important}}@media screen and (min-width:769px),print{.has-text-right-tablet{text-align:right!important}}@media screen and (min-width:769px) and (max-width:1023px){.has-text-right-tablet-only{text-align:right!important}}@media screen and (max-width:1023px){.has-text-right-touch{text-align:right!important}}@media screen and (min-width:1024px){.has-text-right-desktop{text-align:right!important}}@media screen and (min-width:1024px) and (max-width:1215px){.has-text-right-desktop-only{text-align:right!important}}@media screen and (min-width:1216px){.has-text-right-widescreen{text-align:right!important}}@media screen and (min-width:1216px) and (max-width:1407px){.has-text-right-widescreen-only{text-align:right!important}}@media screen and (min-width:1408px){.has-text-right-fullhd{text-align:right!important}}.is-capitalized{text-transform:capitalize!important}.is-lowercase{text-transform:lowercase!important}.is-uppercase{text-transform:uppercase!important}.is-italic{font-style:italic!important}.is-underlined{text-decoration:underline!important}.has-text-weight-light{font-weight:300!important}.has-text-weight-normal{font-weight:400!important}.has-text-weight-medium{font-weight:500!important}.has-text-weight-semibold{font-weight:600!important}.has-text-weight-bold{font-weight:700!important}.is-family-primary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-secondary{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-sans-serif{font-family:BlinkMacSystemFont,-apple-system,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Fira Sans","Droid Sans","Helvetica Neue",Helvetica,Arial,sans-serif!important}.is-family-monospace{font-family:monospace!important}.is-family-code{font-family:monospace!important}.is-block{display:block!important}@media screen and (max-width:768px){.is-block-mobile{display:block!important}}@media screen and (min-width:769px),print{.is-block-tablet{display:block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-block-tablet-only{display:block!important}}@media screen and (max-width:1023px){.is-block-touch{display:block!important}}@media screen and (min-width:1024px){.is-block-desktop{display:block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-block-desktop-only{display:block!important}}@media screen and (min-width:1216px){.is-block-widescreen{display:block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-block-widescreen-only{display:block!important}}@media screen and (min-width:1408px){.is-block-fullhd{display:block!important}}.is-flex{display:flex!important}@media screen and (max-width:768px){.is-flex-mobile{display:flex!important}}@media screen and (min-width:769px),print{.is-flex-tablet{display:flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-flex-tablet-only{display:flex!important}}@media screen and (max-width:1023px){.is-flex-touch{display:flex!important}}@media screen and (min-width:1024px){.is-flex-desktop{display:flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-flex-desktop-only{display:flex!important}}@media screen and (min-width:1216px){.is-flex-widescreen{display:flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-flex-widescreen-only{display:flex!important}}@media screen and (min-width:1408px){.is-flex-fullhd{display:flex!important}}.is-inline{display:inline!important}@media screen and (max-width:768px){.is-inline-mobile{display:inline!important}}@media screen and (min-width:769px),print{.is-inline-tablet{display:inline!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-tablet-only{display:inline!important}}@media screen and (max-width:1023px){.is-inline-touch{display:inline!important}}@media screen and (min-width:1024px){.is-inline-desktop{display:inline!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-desktop-only{display:inline!important}}@media screen and (min-width:1216px){.is-inline-widescreen{display:inline!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-widescreen-only{display:inline!important}}@media screen and (min-width:1408px){.is-inline-fullhd{display:inline!important}}.is-inline-block{display:inline-block!important}@media screen and (max-width:768px){.is-inline-block-mobile{display:inline-block!important}}@media screen and (min-width:769px),print{.is-inline-block-tablet{display:inline-block!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-block-tablet-only{display:inline-block!important}}@media screen and (max-width:1023px){.is-inline-block-touch{display:inline-block!important}}@media screen and (min-width:1024px){.is-inline-block-desktop{display:inline-block!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-block-desktop-only{display:inline-block!important}}@media screen and (min-width:1216px){.is-inline-block-widescreen{display:inline-block!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-block-widescreen-only{display:inline-block!important}}@media screen and (min-width:1408px){.is-inline-block-fullhd{display:inline-block!important}}.is-inline-flex{display:inline-flex!important}@media screen and (max-width:768px){.is-inline-flex-mobile{display:inline-flex!important}}@media screen and (min-width:769px),print{.is-inline-flex-tablet{display:inline-flex!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-inline-flex-tablet-only{display:inline-flex!important}}@media screen and (max-width:1023px){.is-inline-flex-touch{display:inline-flex!important}}@media screen and (min-width:1024px){.is-inline-flex-desktop{display:inline-flex!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-inline-flex-desktop-only{display:inline-flex!important}}@media screen and (min-width:1216px){.is-inline-flex-widescreen{display:inline-flex!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-inline-flex-widescreen-only{display:inline-flex!important}}@media screen and (min-width:1408px){.is-inline-flex-fullhd{display:inline-flex!important}}.is-hidden{display:none!important}.is-sr-only{border:none!important;clip:rect(0,0,0,0)!important;height:.01em!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:.01em!important}@media screen and (max-width:768px){.is-hidden-mobile{display:none!important}}@media screen and (min-width:769px),print{.is-hidden-tablet{display:none!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-hidden-tablet-only{display:none!important}}@media screen and (max-width:1023px){.is-hidden-touch{display:none!important}}@media screen and (min-width:1024px){.is-hidden-desktop{display:none!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-hidden-desktop-only{display:none!important}}@media screen and (min-width:1216px){.is-hidden-widescreen{display:none!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-hidden-widescreen-only{display:none!important}}@media screen and (min-width:1408px){.is-hidden-fullhd{display:none!important}}.is-invisible{visibility:hidden!important}@media screen and (max-width:768px){.is-invisible-mobile{visibility:hidden!important}}@media screen and (min-width:769px),print{.is-invisible-tablet{visibility:hidden!important}}@media screen and (min-width:769px) and (max-width:1023px){.is-invisible-tablet-only{visibility:hidden!important}}@media screen and (max-width:1023px){.is-invisible-touch{visibility:hidden!important}}@media screen and (min-width:1024px){.is-invisible-desktop{visibility:hidden!important}}@media screen and (min-width:1024px) and (max-width:1215px){.is-invisible-desktop-only{visibility:hidden!important}}@media screen and (min-width:1216px){.is-invisible-widescreen{visibility:hidden!important}}@media screen and (min-width:1216px) and (max-width:1407px){.is-invisible-widescreen-only{visibility:hidden!important}}@media screen and (min-width:1408px){.is-invisible-fullhd{visibility:hidden!important}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:0 0}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width:1023px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,.7)}.hero.is-white .navbar-link.is-active,.hero.is-white .navbar-link:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white a.navbar-item:hover{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff!important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg,#e6e6e6 0,#fff 71%,#fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,.7)}.hero.is-black .navbar-link.is-active,.hero.is-black .navbar-link:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black a.navbar-item:hover{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a!important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}@media screen and (max-width:768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg,#000 0,#0a0a0a 71%,#181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,.7)}.hero.is-light .subtitle{color:rgba(0,0,0,.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,.7)}.hero.is-light .navbar-link.is-active,.hero.is-light .navbar-link:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light a.navbar-item:hover{background-color:#e8e8e8;color:rgba(0,0,0,.7)}.hero.is-light .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5!important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}@media screen and (max-width:768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg,#dfd8d9 0,#f5f5f5 71%,#fff 100%)}}.hero.is-dark{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#fff}.hero.is-dark .subtitle{color:rgba(255,255,255,.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(255,255,255,.7)}.hero.is-dark .navbar-link.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark a.navbar-item:hover{background-color:#292929;color:#fff}.hero.is-dark .tabs a{color:#fff;opacity:.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{color:#363636!important;opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}@media screen and (max-width:768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg,#1f191a 0,#363636 71%,#46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,.7)}.hero.is-primary .navbar-link.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary a.navbar-item:hover{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{color:#00d1b2!important;opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}@media screen and (max-width:768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg,#009e6c 0,#00d1b2 71%,#00e7eb 100%)}}.hero.is-link{background-color:#485fc7;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-link .navbar-menu{background-color:#485fc7}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,.7)}.hero.is-link .navbar-link.is-active,.hero.is-link .navbar-link:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link a.navbar-item:hover{background-color:#3a51bb;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#485fc7!important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#485fc7}.hero.is-link.is-bold{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}@media screen and (max-width:768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg,#2959b3 0,#485fc7 71%,#5658d2 100%)}}.hero.is-info{background-color:#3e8ed0;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-info .navbar-menu{background-color:#3e8ed0}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,.7)}.hero.is-info .navbar-link.is-active,.hero.is-info .navbar-link:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info a.navbar-item:hover{background-color:#3082c5;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#3e8ed0!important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3e8ed0}.hero.is-info.is-bold{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}@media screen and (max-width:768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg,#208fbc 0,#3e8ed0 71%,#4d83db 100%)}}.hero.is-success{background-color:#48c78e;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-success .navbar-menu{background-color:#48c78e}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,.7)}.hero.is-success .navbar-link.is-active,.hero.is-success .navbar-link:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success a.navbar-item:hover{background-color:#3abb81;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#48c78e!important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#48c78e}.hero.is-success.is-bold{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}@media screen and (max-width:768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg,#29b35e 0,#48c78e 71%,#56d2af 100%)}}.hero.is-warning{background-color:#ffe08a;color:rgba(0,0,0,.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,.7)}@media screen and (max-width:1023px){.hero.is-warning .navbar-menu{background-color:#ffe08a}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,.7)}.hero.is-warning .navbar-link.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning a.navbar-item:hover{background-color:#ffd970;color:rgba(0,0,0,.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,.7);opacity:.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffe08a!important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,.7);border-color:rgba(0,0,0,.7);color:#ffe08a}.hero.is-warning.is-bold{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}@media screen and (max-width:768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg,#ffb657 0,#ffe08a 71%,#fff6a3 100%)}}.hero.is-danger{background-color:#f14668;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width:1023px){.hero.is-danger .navbar-menu{background-color:#f14668}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,.7)}.hero.is-danger .navbar-link.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger a.navbar-item:hover{background-color:#ef2e55;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#f14668!important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#f14668}.hero.is-danger.is-bold{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}@media screen and (max-width:768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg,#fa0a62 0,#f14668 71%,#f7595f 100%)}}.hero.is-small .hero-body{padding:1.5rem}@media screen and (min-width:769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width:769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body,.hero.is-halfheight .hero-body{align-items:center;display:flex}.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container,.hero.is-halfheight .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%,-50%,0)}.hero-video.is-transparent{opacity:.3}@media screen and (max-width:768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width:768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:.75rem}}@media screen and (min-width:769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-foot,.hero-head{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width:769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width:1024px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem} \ No newline at end of file diff --git a/templ/examples/counter/assets/favicon/about.txt b/templ/examples/counter/assets/favicon/about.txt new file mode 100644 index 0000000..7d6aedf --- /dev/null +++ b/templ/examples/counter/assets/favicon/about.txt @@ -0,0 +1,6 @@ +This favicon was generated using the following font: + +- Font Title: Leckerli One +- Font Author: Copyright (c) 2011 Gesine Todt (www.gesine-todt.de), with Reserved Font Names "Leckerli" +- Font Source: http://fonts.gstatic.com/s/leckerlione/v16/V8mCoQH8VCsNttEnxnGQ-1itLZxcBtItFw.ttf +- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL)) diff --git a/templ/examples/counter/assets/favicon/android-chrome-192x192.png b/templ/examples/counter/assets/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..e218b89 Binary files /dev/null and b/templ/examples/counter/assets/favicon/android-chrome-192x192.png differ diff --git a/templ/examples/counter/assets/favicon/android-chrome-512x512.png b/templ/examples/counter/assets/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..f02fe55 Binary files /dev/null and b/templ/examples/counter/assets/favicon/android-chrome-512x512.png differ diff --git a/templ/examples/counter/assets/favicon/apple-touch-icon.png b/templ/examples/counter/assets/favicon/apple-touch-icon.png new file mode 100644 index 0000000..1f51b01 Binary files /dev/null and b/templ/examples/counter/assets/favicon/apple-touch-icon.png differ diff --git a/templ/examples/counter/assets/favicon/favicon-16x16.png b/templ/examples/counter/assets/favicon/favicon-16x16.png new file mode 100644 index 0000000..63b5d9e Binary files /dev/null and b/templ/examples/counter/assets/favicon/favicon-16x16.png differ diff --git a/templ/examples/counter/assets/favicon/favicon-32x32.png b/templ/examples/counter/assets/favicon/favicon-32x32.png new file mode 100644 index 0000000..45de0e0 Binary files /dev/null and b/templ/examples/counter/assets/favicon/favicon-32x32.png differ diff --git a/templ/examples/counter/assets/favicon/favicon.ico b/templ/examples/counter/assets/favicon/favicon.ico new file mode 100644 index 0000000..f29ddcc Binary files /dev/null and b/templ/examples/counter/assets/favicon/favicon.ico differ diff --git a/templ/examples/counter/assets/favicon/site.webmanifest b/templ/examples/counter/assets/favicon/site.webmanifest new file mode 100644 index 0000000..67ed3d1 --- /dev/null +++ b/templ/examples/counter/assets/favicon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/assets/favicon/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/assets/favicon/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} diff --git a/templ/examples/counter/assets/images/logo.png b/templ/examples/counter/assets/images/logo.png new file mode 100644 index 0000000..cf9411a Binary files /dev/null and b/templ/examples/counter/assets/images/logo.png differ diff --git a/templ/examples/counter/assets/js/htmx.min.js b/templ/examples/counter/assets/js/htmx.min.js new file mode 100644 index 0000000..7c6666a --- /dev/null +++ b/templ/examples/counter/assets/js/htmx.min.js @@ -0,0 +1 @@ +(function(e,t){if(typeof define==="function"&&define.amd){define([],t)}else if(typeof module==="object"&&module.exports){module.exports=t()}else{e.htmx=e.htmx||t()}})(typeof self!=="undefined"?self:this,function(){return function(){"use strict";var z={onLoad:t,process:Tt,on:le,off:ue,trigger:ie,ajax:dr,find:b,findAll:f,closest:d,values:function(e,t){var r=Jt(e,t||"post");return r.values},remove:B,addClass:j,removeClass:n,toggleClass:U,takeClass:V,defineExtension:yr,removeExtension:br,logAll:F,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,inlineScriptNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",useTemplateFragments:false,scrollBehavior:"smooth",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false},parseInterval:v,_:e,createEventSource:function(e){return new EventSource(e,{withCredentials:true})},createWebSocket:function(e){var t=new WebSocket(e,[]);t.binaryType=z.config.wsBinaryType;return t},version:"1.9.2"};var C={addTriggerHandler:xt,bodyContains:ee,canAccessLocalStorage:D,filterValues:er,hasAttribute:q,getAttributeValue:G,getClosestMatch:c,getExpressionVars:fr,getHeaders:Qt,getInputValues:Jt,getInternalData:Y,getSwapSpecification:rr,getTriggerSpecs:ze,getTarget:de,makeFragment:l,mergeObjects:te,makeSettleInfo:S,oobSwap:me,selectAndSwap:Me,settleImmediately:Bt,shouldCancel:Ke,triggerEvent:ie,triggerErrorEvent:ne,withExtensions:w};var R=["get","post","put","delete","patch"];var O=R.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function v(e){if(e==undefined){return undefined}if(e.slice(-2)=="ms"){return parseFloat(e.slice(0,-2))||undefined}if(e.slice(-1)=="s"){return parseFloat(e.slice(0,-1))*1e3||undefined}if(e.slice(-1)=="m"){return parseFloat(e.slice(0,-1))*1e3*60||undefined}return parseFloat(e)||undefined}function $(e,t){return e.getAttribute&&e.getAttribute(t)}function q(e,t){return e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function G(e,t){return $(e,t)||$(e,"data-"+t)}function u(e){return e.parentElement}function J(){return document}function c(e,t){while(e&&!t(e)){e=u(e)}return e?e:null}function T(e,t,r){var n=G(t,r);var i=G(t,"hx-disinherit");if(e!==t&&i&&(i==="*"||i.split(" ").indexOf(r)>=0)){return"unset"}else{return n}}function Z(t,r){var n=null;c(t,function(e){return n=T(t,e,r)});if(n!=="unset"){return n}}function h(e,t){var r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector;return r&&r.call(e,t)}function H(e){var t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;var r=t.exec(e);if(r){return r[1].toLowerCase()}else{return""}}function i(e,t){var r=new DOMParser;var n=r.parseFromString(e,"text/html");var i=n.body;while(t>0){t--;i=i.firstChild}if(i==null){i=J().createDocumentFragment()}return i}function L(e){return e.match(/",0);return r.querySelector("template").content}else{var n=H(e);switch(n){case"thead":case"tbody":case"tfoot":case"colgroup":case"caption":return i(""+e+"
",1);case"col":return i(""+e+"
",2);case"tr":return i(""+e+"
",2);case"td":case"th":return i(""+e+"
",3);case"script":return i("
"+e+"
",1);default:return i(e,0)}}}function K(e){if(e){e()}}function A(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function N(e){return A(e,"Function")}function I(e){return A(e,"Object")}function Y(e){var t="htmx-internal-data";var r=e[t];if(!r){r=e[t]={}}return r}function k(e){var t=[];if(e){for(var r=0;r=0}function ee(e){if(e.getRootNode&&e.getRootNode()instanceof ShadowRoot){return J().body.contains(e.getRootNode().host)}else{return J().body.contains(e)}}function M(e){return e.trim().split(/\s+/)}function te(e,t){for(var r in t){if(t.hasOwnProperty(r)){e[r]=t[r]}}return e}function y(e){try{return JSON.parse(e)}catch(e){x(e);return null}}function D(){var e="htmx:localStorageTest";try{localStorage.setItem(e,e);localStorage.removeItem(e);return true}catch(e){return false}}function X(t){try{var e=new URL(t);if(e){t=e.pathname+e.search}if(!t.match("^/$")){t=t.replace(/\/+$/,"")}return t}catch(e){return t}}function e(e){return sr(J().body,function(){return eval(e)})}function t(t){var e=z.on("htmx:load",function(e){t(e.detail.elt)});return e}function F(){z.logger=function(e,t,r){if(console){console.log(t,e,r)}}}function b(e,t){if(t){return e.querySelector(t)}else{return b(J(),e)}}function f(e,t){if(t){return e.querySelectorAll(t)}else{return f(J(),e)}}function B(e,t){e=s(e);if(t){setTimeout(function(){B(e);e=null},t)}else{e.parentElement.removeChild(e)}}function j(e,t,r){e=s(e);if(r){setTimeout(function(){j(e,t);e=null},r)}else{e.classList&&e.classList.add(t)}}function n(e,t,r){e=s(e);if(r){setTimeout(function(){n(e,t);e=null},r)}else{if(e.classList){e.classList.remove(t);if(e.classList.length===0){e.removeAttribute("class")}}}}function U(e,t){e=s(e);e.classList.toggle(t)}function V(e,t){e=s(e);Q(e.parentElement.children,function(e){n(e,t)});j(e,t)}function d(e,t){e=s(e);if(e.closest){return e.closest(t)}else{do{if(e==null||h(e,t)){return e}}while(e=e&&u(e));return null}}function r(e){var t=e.trim();if(t.startsWith("<")&&t.endsWith("/>")){return t.substring(1,t.length-2)}else{return t}}function _(e,t){if(t.indexOf("closest ")===0){return[d(e,r(t.substr(8)))]}else if(t.indexOf("find ")===0){return[b(e,r(t.substr(5)))]}else if(t.indexOf("next ")===0){return[W(e,r(t.substr(5)))]}else if(t.indexOf("previous ")===0){return[oe(e,r(t.substr(9)))]}else if(t==="document"){return[document]}else if(t==="window"){return[window]}else{return J().querySelectorAll(r(t))}}var W=function(e,t){var r=J().querySelectorAll(t);for(var n=0;n=0;n--){var i=r[n];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING){return i}}};function re(e,t){if(t){return _(e,t)[0]}else{return _(J().body,e)[0]}}function s(e){if(A(e,"String")){return b(e)}else{return e}}function se(e,t,r){if(N(t)){return{target:J().body,event:e,listener:t}}else{return{target:s(e),event:t,listener:r}}}function le(t,r,n){Sr(function(){var e=se(t,r,n);e.target.addEventListener(e.event,e.listener)});var e=N(r);return e?r:n}function ue(t,r,n){Sr(function(){var e=se(t,r,n);e.target.removeEventListener(e.event,e.listener)});return N(r)?r:n}var fe=J().createElement("output");function ce(e,t){var r=Z(e,t);if(r){if(r==="this"){return[he(e,t)]}else{var n=_(e,r);if(n.length===0){x('The selector "'+r+'" on '+t+" returned no matches!");return[fe]}else{return n}}}}function he(e,t){return c(e,function(e){return G(e,t)!=null})}function de(e){var t=Z(e,"hx-target");if(t){if(t==="this"){return he(e,"hx-target")}else{return re(e,t)}}else{var r=Y(e);if(r.boosted){return J().body}else{return e}}}function ve(e){var t=z.config.attributesToSettle;for(var r=0;r0){o=e.substr(0,e.indexOf(":"));t=e.substr(e.indexOf(":")+1,e.length)}else{o=e}var r=J().querySelectorAll(t);if(r){Q(r,function(e){var t;var r=i.cloneNode(true);t=J().createDocumentFragment();t.appendChild(r);if(!pe(o,e)){t=r}var n={shouldSwap:true,target:e,fragment:t};if(!ie(e,"htmx:oobBeforeSwap",n))return;e=n.target;if(n["shouldSwap"]){ke(o,e,e,t,a)}Q(a.elts,function(e){ie(e,"htmx:oobAfterSwap",n)})});i.parentNode.removeChild(i)}else{i.parentNode.removeChild(i);ne(J().body,"htmx:oobErrorNoTarget",{content:i})}return e}function xe(e,t,r){var n=Z(e,"hx-select-oob");if(n){var i=n.split(",");for(let e=0;e0){var t=e.id.replace("'","\\'");var r=e.tagName.replace(":","\\:");var n=a.querySelector(r+"[id='"+t+"']");if(n&&n!==a){var i=e.cloneNode();ge(e,n);o.tasks.push(function(){ge(e,i)})}}})}function we(e){return function(){n(e,z.config.addedClass);Tt(e);bt(e);Se(e);ie(e,"htmx:load")}}function Se(e){var t="[autofocus]";var r=h(e,t)?e:e.querySelector(t);if(r!=null){r.focus()}}function a(e,t,r,n){be(e,r,n);while(r.childNodes.length>0){var i=r.firstChild;j(i,z.config.addedClass);e.insertBefore(i,t);if(i.nodeType!==Node.TEXT_NODE&&i.nodeType!==Node.COMMENT_NODE){n.tasks.push(we(i))}}}function Ee(e,t){var r=0;while(r-1){var t=e.replace(/]*>|>)([\s\S]*?)<\/svg>/gim,"");var r=t.match(/]*>|>)([\s\S]*?)<\/title>/im);if(r){return r[2]}}}function Me(e,t,r,n,i){i.title=Pe(n);var a=l(n);if(a){xe(r,a,i);a=Ie(r,a);ye(a);return ke(e,r,t,a,i)}}function De(e,t,r){var n=e.getResponseHeader(t);if(n.indexOf("{")===0){var i=y(n);for(var a in i){if(i.hasOwnProperty(a)){var o=i[a];if(!I(o)){o={value:o}}ie(r,a,o)}}}else{ie(r,n,[])}}var Xe=/\s/;var g=/[\s,]/;var Fe=/[_$a-zA-Z]/;var Be=/[_$a-zA-Z0-9]/;var je=['"',"'","/"];var p=/[^\s]/;function Ue(e){var t=[];var r=0;while(r0){var o=t[0];if(o==="]"){n--;if(n===0){if(a===null){i=i+"true"}t.shift();i+=")})";try{var s=sr(e,function(){return Function(i)()},function(){return true});s.source=i;return s}catch(e){ne(J().body,"htmx:syntax:error",{error:e,source:i});return null}}}else if(o==="["){n++}if(Ve(o,a,r)){i+="(("+r+"."+o+") ? ("+r+"."+o+") : (window."+o+"))"}else{i=i+o}a=t.shift()}}}function m(e,t){var r="";while(e.length>0&&!e[0].match(t)){r+=e.shift()}return r}var We="input, textarea, select";function ze(e){var t=G(e,"hx-trigger");var r=[];if(t){var n=Ue(t);do{m(n,p);var i=n.length;var a=m(n,/[,\[\s]/);if(a!==""){if(a==="every"){var o={trigger:"every"};m(n,p);o.pollInterval=v(m(n,/[,\[\s]/));m(n,p);var s=_e(e,n,"event");if(s){o.eventFilter=s}r.push(o)}else if(a.indexOf("sse:")===0){r.push({trigger:"sse",sseEvent:a.substr(4)})}else{var l={trigger:a};var s=_e(e,n,"event");if(s){l.eventFilter=s}while(n.length>0&&n[0]!==","){m(n,p);var u=n.shift();if(u==="changed"){l.changed=true}else if(u==="once"){l.once=true}else if(u==="consume"){l.consume=true}else if(u==="delay"&&n[0]===":"){n.shift();l.delay=v(m(n,g))}else if(u==="from"&&n[0]===":"){n.shift();var f=m(n,g);if(f==="closest"||f==="find"||f==="next"||f==="previous"){n.shift();f+=" "+m(n,g)}l.from=f}else if(u==="target"&&n[0]===":"){n.shift();l.target=m(n,g)}else if(u==="throttle"&&n[0]===":"){n.shift();l.throttle=v(m(n,g))}else if(u==="queue"&&n[0]===":"){n.shift();l.queue=m(n,g)}else if((u==="root"||u==="threshold")&&n[0]===":"){n.shift();l[u]=m(n,g)}else{ne(e,"htmx:syntax:error",{token:n.shift()})}}r.push(l)}}if(n.length===i){ne(e,"htmx:syntax:error",{token:n.shift()})}m(n,p)}while(n[0]===","&&n.shift())}if(r.length>0){return r}else if(h(e,"form")){return[{trigger:"submit"}]}else if(h(e,'input[type="button"]')){return[{trigger:"click"}]}else if(h(e,We)){return[{trigger:"change"}]}else{return[{trigger:"click"}]}}function $e(e){Y(e).cancelled=true}function Ge(e,t,r){var n=Y(e);n.timeout=setTimeout(function(){if(ee(e)&&n.cancelled!==true){if(!Qe(r,Lt("hx:poll:trigger",{triggerSpec:r,target:e}))){t(e)}Ge(e,t,r)}},r.pollInterval)}function Je(e){return location.hostname===e.hostname&&$(e,"href")&&$(e,"href").indexOf("#")!==0}function Ze(t,r,e){if(t.tagName==="A"&&Je(t)&&(t.target===""||t.target==="_self")||t.tagName==="FORM"){r.boosted=true;var n,i;if(t.tagName==="A"){n="get";i=t.href}else{var a=$(t,"method");n=a?a.toLowerCase():"get";if(n==="get"){}i=$(t,"action")}e.forEach(function(e){et(t,function(e,t){ae(n,i,e,t)},r,e,true)})}}function Ke(e,t){if(e.type==="submit"||e.type==="click"){if(t.tagName==="FORM"){return true}if(h(t,'input[type="submit"], button')&&d(t,"form")!==null){return true}if(t.tagName==="A"&&t.href&&(t.getAttribute("href")==="#"||t.getAttribute("href").indexOf("#")!==0)){return true}}return false}function Ye(e,t){return Y(e).boosted&&e.tagName==="A"&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function Qe(e,t){var r=e.eventFilter;if(r){try{return r(t)!==true}catch(e){ne(J().body,"htmx:eventFilter:error",{error:e,source:r.source});return true}}return false}function et(i,a,e,o,s){var l=Y(i);var t;if(o.from){t=_(i,o.from)}else{t=[i]}if(o.changed){l.lastValue=i.value}Q(t,function(r){var n=function(e){if(!ee(i)){r.removeEventListener(o.trigger,n);return}if(Ye(i,e)){return}if(s||Ke(e,i)){e.preventDefault()}if(Qe(o,e)){return}var t=Y(e);t.triggerSpec=o;if(t.handledFor==null){t.handledFor=[]}if(t.handledFor.indexOf(i)<0){t.handledFor.push(i);if(o.consume){e.stopPropagation()}if(o.target&&e.target){if(!h(e.target,o.target)){return}}if(o.once){if(l.triggeredOnce){return}else{l.triggeredOnce=true}}if(o.changed){if(l.lastValue===i.value){return}else{l.lastValue=i.value}}if(l.delayed){clearTimeout(l.delayed)}if(l.throttle){return}if(o.throttle){if(!l.throttle){a(i,e);l.throttle=setTimeout(function(){l.throttle=null},o.throttle)}}else if(o.delay){l.delayed=setTimeout(function(){a(i,e)},o.delay)}else{ie(i,"htmx:trigger");a(i,e)}}};if(e.listenerInfos==null){e.listenerInfos=[]}e.listenerInfos.push({trigger:o.trigger,listener:n,on:r});r.addEventListener(o.trigger,n)})}var tt=false;var rt=null;function nt(){if(!rt){rt=function(){tt=true};window.addEventListener("scroll",rt);setInterval(function(){if(tt){tt=false;Q(J().querySelectorAll("[hx-trigger='revealed'],[data-hx-trigger='revealed']"),function(e){it(e)})}},200)}}function it(t){if(!q(t,"data-hx-revealed")&&P(t)){t.setAttribute("data-hx-revealed","true");var e=Y(t);if(e.initHash){ie(t,"revealed")}else{t.addEventListener("htmx:afterProcessNode",function(e){ie(t,"revealed")},{once:true})}}}function at(e,t,r){var n=M(r);for(var i=0;i=0){var t=ut(n);setTimeout(function(){ot(s,r,n+1)},t)}};t.onopen=function(e){n=0};Y(s).webSocket=t;t.addEventListener("message",function(e){if(st(s)){return}var t=e.data;w(s,function(e){t=e.transformResponse(t,null,s)});var r=S(s);var n=l(t);var i=k(n.children);for(var a=0;a0){ie(u,"htmx:validation:halted",i);return}t.send(JSON.stringify(l));if(Ke(e,u)){e.preventDefault()}})}else{ne(u,"htmx:noWebSocketSourceError")}}function ut(e){var t=z.config.wsReconnectDelay;if(typeof t==="function"){return t(e)}if(t==="full-jitter"){var r=Math.min(e,6);var n=1e3*Math.pow(2,r);return n*Math.random()}x('htmx.config.wsReconnectDelay must either be a function or the string "full-jitter"')}function ft(e,t,r){var n=M(r);for(var i=0;i0){var o=n.shift();var s=o.match(/^\s*([a-zA-Z:\-]+:)(.*)/);if(a===0&&s){o.split(":");i=s[1].slice(0,-1);r[i]=s[2]}else{r[i]+=o}a+=Ct(o)}for(var l in r){Rt(e,l,r[l])}}}function qt(t){if(t.closest&&t.closest(z.config.disableSelector)){return}var r=Y(t);if(r.initHash!==Ce(t)){r.initHash=Ce(t);Re(t);Ot(t);ie(t,"htmx:beforeProcessNode");if(t.value){r.lastValue=t.value}var e=ze(t);var n=mt(t,r,e);if(!n){if(Z(t,"hx-boost")==="true"){Ze(t,r,e)}else if(q(t,"hx-trigger")){e.forEach(function(e){xt(t,e,r,function(){})})}}if(t.tagName==="FORM"){Et(t)}var i=G(t,"hx-sse");if(i){ft(t,r,i)}var a=G(t,"hx-ws");if(a){at(t,r,a)}ie(t,"htmx:afterProcessNode")}}function Tt(e){e=s(e);qt(e);Q(St(e),function(e){qt(e)})}function Ht(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function Lt(e,t){var r;if(window.CustomEvent&&typeof window.CustomEvent==="function"){r=new CustomEvent(e,{bubbles:true,cancelable:true,detail:t})}else{r=J().createEvent("CustomEvent");r.initCustomEvent(e,true,true,t)}return r}function ne(e,t,r){ie(e,t,te({error:t},r))}function At(e){return e==="htmx:afterProcessNode"}function w(e,t){Q(wr(e),function(e){try{t(e)}catch(e){x(e)}})}function x(e){if(console.error){console.error(e)}else if(console.log){console.log("ERROR: ",e)}}function ie(e,t,r){e=s(e);if(r==null){r={}}r["elt"]=e;var n=Lt(t,r);if(z.logger&&!At(t)){z.logger(e,t,r)}if(r.error){x(r.error);ie(e,"htmx:error",{errorInfo:r})}var i=e.dispatchEvent(n);var a=Ht(t);if(i&&a!==t){var o=Lt(a,n.detail);i=i&&e.dispatchEvent(o)}w(e,function(e){i=i&&e.onEvent(t,n)!==false});return i}var Nt=location.pathname+location.search;function It(){var e=J().querySelector("[hx-history-elt],[data-hx-history-elt]");return e||J().body}function kt(e,t,r,n){if(!D()){return}e=X(e);var i=y(localStorage.getItem("htmx-history-cache"))||[];for(var a=0;az.config.historyCacheSize){i.shift()}while(i.length>0){try{localStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(e){ne(J().body,"htmx:historyCacheError",{cause:e,cache:i});i.shift()}}}function Pt(e){if(!D()){return null}e=X(e);var t=y(localStorage.getItem("htmx-history-cache"))||[];for(var r=0;r=200&&this.status<400){ie(J().body,"htmx:historyCacheMissLoad",o);var e=l(this.response);e=e.querySelector("[hx-history-elt],[data-hx-history-elt]")||e;var t=It();var r=S(t);var n=Pe(this.response);if(n){var i=b("title");if(i){i.innerHTML=n}else{window.document.title=n}}Ne(t,e,r);Bt(r.tasks);Nt=a;ie(J().body,"htmx:historyRestore",{path:a,cacheMiss:true,serverResponse:this.response})}else{ne(J().body,"htmx:historyCacheMissLoadError",o)}};e.send()}function Ut(e){Dt();e=e||location.pathname+location.search;var t=Pt(e);if(t){var r=l(t.content);var n=It();var i=S(n);Ne(n,r,i);Bt(i.tasks);document.title=t.title;window.scrollTo(0,t.scroll);Nt=e;ie(J().body,"htmx:historyRestore",{path:e,item:t})}else{if(z.config.refreshOnHistoryMiss){window.location.reload(true)}else{jt(e)}}}function Vt(e){var t=ce(e,"hx-indicator");if(t==null){t=[e]}Q(t,function(e){var t=Y(e);t.requestCount=(t.requestCount||0)+1;e.classList["add"].call(e.classList,z.config.requestClass)});return t}function _t(e){Q(e,function(e){var t=Y(e);t.requestCount=(t.requestCount||0)-1;if(t.requestCount===0){e.classList["remove"].call(e.classList,z.config.requestClass)}})}function Wt(e,t){for(var r=0;r=0}function rr(e,t){var r=t?t:Z(e,"hx-swap");var n={swapStyle:Y(e).boosted?"innerHTML":z.config.defaultSwapStyle,swapDelay:z.config.defaultSwapDelay,settleDelay:z.config.defaultSettleDelay};if(Y(e).boosted&&!tr(e)){n["show"]="top"}if(r){var i=M(r);if(i.length>0){n["swapStyle"]=i[0];for(var a=1;a0?l.join(":"):null;n["scroll"]=u;n["scrollTarget"]=f}if(o.indexOf("show:")===0){var c=o.substr(5);var l=c.split(":");var h=l.pop();var f=l.length>0?l.join(":"):null;n["show"]=h;n["showTarget"]=f}if(o.indexOf("focus-scroll:")===0){var d=o.substr("focus-scroll:".length);n["focusScroll"]=d=="true"}}}}return n}function nr(e){return Z(e,"hx-encoding")==="multipart/form-data"||h(e,"form")&&$(e,"enctype")==="multipart/form-data"}function ir(t,r,n){var i=null;w(r,function(e){if(i==null){i=e.encodeParameters(t,n,r)}});if(i!=null){return i}else{if(nr(r)){return Yt(n)}else{return Kt(n)}}}function S(e){return{tasks:[],elts:[e]}}function ar(e,t){var r=e[0];var n=e[e.length-1];if(t.scroll){var i=null;if(t.scrollTarget){i=re(r,t.scrollTarget)}if(t.scroll==="top"&&(r||i)){i=i||r;i.scrollTop=0}if(t.scroll==="bottom"&&(n||i)){i=i||n;i.scrollTop=i.scrollHeight}}if(t.show){var i=null;if(t.showTarget){var a=t.showTarget;if(t.showTarget==="window"){a="body"}i=re(r,a)}if(t.show==="top"&&(r||i)){i=i||r;i.scrollIntoView({block:"start",behavior:z.config.scrollBehavior})}if(t.show==="bottom"&&(n||i)){i=i||n;i.scrollIntoView({block:"end",behavior:z.config.scrollBehavior})}}}function or(e,t,r,n){if(n==null){n={}}if(e==null){return n}var i=G(e,t);if(i){var a=i.trim();var o=r;if(a==="unset"){return null}if(a.indexOf("javascript:")===0){a=a.substr(11);o=true}else if(a.indexOf("js:")===0){a=a.substr(3);o=true}if(a.indexOf("{")!==0){a="{"+a+"}"}var s;if(o){s=sr(e,function(){return Function("return ("+a+")")()},{})}else{s=y(a)}for(var l in s){if(s.hasOwnProperty(l)){if(n[l]==null){n[l]=s[l]}}}}return or(u(e),t,r,n)}function sr(e,t,r){if(z.config.allowEval){return t()}else{ne(e,"htmx:evalDisallowedError");return r}}function lr(e,t){return or(e,"hx-vars",true,t)}function ur(e,t){return or(e,"hx-vals",false,t)}function fr(e){return te(lr(e),ur(e))}function cr(t,r,n){if(n!==null){try{t.setRequestHeader(r,n)}catch(e){t.setRequestHeader(r,encodeURIComponent(n));t.setRequestHeader(r+"-URI-AutoEncoded","true")}}}function hr(t){if(t.responseURL&&typeof URL!=="undefined"){try{var e=new URL(t.responseURL);return e.pathname+e.search}catch(e){ne(J().body,"htmx:badResponseUrl",{url:t.responseURL})}}}function E(e,t){return e.getAllResponseHeaders().match(t)}function dr(e,t,r){e=e.toLowerCase();if(r){if(r instanceof Element||A(r,"String")){return ae(e,t,null,null,{targetOverride:s(r),returnPromise:true})}else{return ae(e,t,s(r.source),r.event,{handler:r.handler,headers:r.headers,values:r.values,targetOverride:s(r.target),swapOverride:r.swap,returnPromise:true})}}else{return ae(e,t,null,null,{returnPromise:true})}}function vr(e){var t=[];while(e){t.push(e);e=e.parentElement}return t}function ae(e,t,n,r,i,M){var a=null;var o=null;i=i!=null?i:{};if(i.returnPromise&&typeof Promise!=="undefined"){var s=new Promise(function(e,t){a=e;o=t})}if(n==null){n=J().body}var D=i.handler||pr;if(!ee(n)){return}var l=i.targetOverride||de(n);if(l==null||l==fe){ne(n,"htmx:targetError",{target:G(n,"hx-target")});return}if(!M){var X=function(){return ae(e,t,n,r,i,true)};var F={target:l,elt:n,path:t,verb:e,triggeringEvent:r,etc:i,issueRequest:X};if(ie(n,"htmx:confirm",F)===false){return}}var u=n;var f=Y(n);var c=Z(n,"hx-sync");var h=null;var d=false;if(c){var v=c.split(":");var g=v[0].trim();if(g==="this"){u=he(n,"hx-sync")}else{u=re(n,g)}c=(v[1]||"drop").trim();f=Y(u);if(c==="drop"&&f.xhr&&f.abortable!==true){return}else if(c==="abort"){if(f.xhr){return}else{d=true}}else if(c==="replace"){ie(u,"htmx:abort")}else if(c.indexOf("queue")===0){var B=c.split(" ");h=(B[1]||"last").trim()}}if(f.xhr){if(f.abortable){ie(u,"htmx:abort")}else{if(h==null){if(r){var p=Y(r);if(p&&p.triggerSpec&&p.triggerSpec.queue){h=p.triggerSpec.queue}}if(h==null){h="last"}}if(f.queuedRequests==null){f.queuedRequests=[]}if(h==="first"&&f.queuedRequests.length===0){f.queuedRequests.push(function(){ae(e,t,n,r,i)})}else if(h==="all"){f.queuedRequests.push(function(){ae(e,t,n,r,i)})}else if(h==="last"){f.queuedRequests=[];f.queuedRequests.push(function(){ae(e,t,n,r,i)})}return}}var m=new XMLHttpRequest;f.xhr=m;f.abortable=d;var x=function(){f.xhr=null;f.abortable=false;if(f.queuedRequests!=null&&f.queuedRequests.length>0){var e=f.queuedRequests.shift();e()}};var y=Z(n,"hx-prompt");if(y){var b=prompt(y);if(b===null||!ie(n,"htmx:prompt",{prompt:b,target:l})){K(a);x();return s}}var w=Z(n,"hx-confirm");if(w){if(!confirm(w)){K(a);x();return s}}var S=Qt(n,l,b);if(i.headers){S=te(S,i.headers)}var E=Jt(n,e);var C=E.errors;var R=E.values;if(i.values){R=te(R,i.values)}var j=fr(n);var O=te(R,j);var q=er(O,n);if(e!=="get"&&!nr(n)){S["Content-Type"]="application/x-www-form-urlencoded"}if(z.config.getCacheBusterParam&&e==="get"){q["org.htmx.cache-buster"]=$(l,"id")||"true"}if(t==null||t===""){t=J().location.href}var T=or(n,"hx-request");var H=Y(n).boosted;var L={boosted:H,parameters:q,unfilteredParameters:O,headers:S,target:l,verb:e,errors:C,withCredentials:i.credentials||T.credentials||z.config.withCredentials,timeout:i.timeout||T.timeout||z.config.timeout,path:t,triggeringEvent:r};if(!ie(n,"htmx:configRequest",L)){K(a);x();return s}t=L.path;e=L.verb;S=L.headers;q=L.parameters;C=L.errors;if(C&&C.length>0){ie(n,"htmx:validation:halted",L);K(a);x();return s}var U=t.split("#");var V=U[0];var A=U[1];var N=null;if(e==="get"){N=V;var _=Object.keys(q).length!==0;if(_){if(N.indexOf("?")<0){N+="?"}else{N+="&"}N+=Kt(q);if(A){N+="#"+A}}m.open("GET",N,true)}else{m.open(e.toUpperCase(),t,true)}m.overrideMimeType("text/html");m.withCredentials=L.withCredentials;m.timeout=L.timeout;if(T.noHeaders){}else{for(var I in S){if(S.hasOwnProperty(I)){var W=S[I];cr(m,I,W)}}}var k={xhr:m,target:l,requestConfig:L,etc:i,boosted:H,pathInfo:{requestPath:t,finalRequestPath:N||t,anchor:A}};m.onload=function(){try{var e=vr(n);k.pathInfo.responsePath=hr(m);D(n,k);_t(P);ie(n,"htmx:afterRequest",k);ie(n,"htmx:afterOnLoad",k);if(!ee(n)){var t=null;while(e.length>0&&t==null){var r=e.shift();if(ee(r)){t=r}}if(t){ie(t,"htmx:afterRequest",k);ie(t,"htmx:afterOnLoad",k)}}K(a);x()}catch(e){ne(n,"htmx:onLoadError",te({error:e},k));throw e}};m.onerror=function(){_t(P);ne(n,"htmx:afterRequest",k);ne(n,"htmx:sendError",k);K(o);x()};m.onabort=function(){_t(P);ne(n,"htmx:afterRequest",k);ne(n,"htmx:sendAbort",k);K(o);x()};m.ontimeout=function(){_t(P);ne(n,"htmx:afterRequest",k);ne(n,"htmx:timeout",k);K(o);x()};if(!ie(n,"htmx:beforeRequest",k)){K(a);x();return s}var P=Vt(n);Q(["loadstart","loadend","progress","abort"],function(t){Q([m,m.upload],function(e){e.addEventListener(t,function(e){ie(n,"htmx:xhr:"+t,{lengthComputable:e.lengthComputable,loaded:e.loaded,total:e.total})})})});ie(n,"htmx:beforeSend",k);m.send(e==="get"?null:ir(m,n,q));return s}function gr(e,t){var r=t.xhr;var n=null;var i=null;if(E(r,/HX-Push:/i)){n=r.getResponseHeader("HX-Push");i="push"}else if(E(r,/HX-Push-Url:/i)){n=r.getResponseHeader("HX-Push-Url");i="push"}else if(E(r,/HX-Replace-Url:/i)){n=r.getResponseHeader("HX-Replace-Url");i="replace"}if(n){if(n==="false"){return{}}else{return{type:i,path:n}}}var a=t.pathInfo.finalRequestPath;var o=t.pathInfo.responsePath;var s=Z(e,"hx-push-url");var l=Z(e,"hx-replace-url");var u=Y(e).boosted;var f=null;var c=null;if(s){f="push";c=s}else if(l){f="replace";c=l}else if(u){f="push";c=o||a}if(c){if(c==="false"){return{}}if(c==="true"){c=o||a}if(t.pathInfo.anchor&&c.indexOf("#")===-1){c=c+"#"+t.pathInfo.anchor}return{type:f,path:c}}else{return{}}}function pr(s,l){var u=l.xhr;var f=l.target;var e=l.etc;if(!ie(s,"htmx:beforeOnLoad",l))return;if(E(u,/HX-Trigger:/i)){De(u,"HX-Trigger",s)}if(E(u,/HX-Location:/i)){Dt();var t=u.getResponseHeader("HX-Location");var c;if(t.indexOf("{")===0){c=y(t);t=c["path"];delete c["path"]}dr("GET",t,c).then(function(){Xt(t)});return}if(E(u,/HX-Redirect:/i)){location.href=u.getResponseHeader("HX-Redirect");return}if(E(u,/HX-Refresh:/i)){if("true"===u.getResponseHeader("HX-Refresh")){location.reload();return}}if(E(u,/HX-Retarget:/i)){l.target=J().querySelector(u.getResponseHeader("HX-Retarget"))}var h=gr(s,l);var r=u.status>=200&&u.status<400&&u.status!==204;var d=u.response;var n=u.status>=400;var i=te({shouldSwap:r,serverResponse:d,isError:n},l);if(!ie(f,"htmx:beforeSwap",i))return;f=i.target;d=i.serverResponse;n=i.isError;l.target=f;l.failed=n;l.successful=!n;if(i.shouldSwap){if(u.status===286){$e(s)}w(s,function(e){d=e.transformResponse(d,u,s)});if(h.type){Dt()}var a=e.swapOverride;if(E(u,/HX-Reswap:/i)){a=u.getResponseHeader("HX-Reswap")}var c=rr(s,a);f.classList.add(z.config.swappingClass);var v=null;var g=null;var o=function(){try{var e=document.activeElement;var t={};try{t={elt:e,start:e?e.selectionStart:null,end:e?e.selectionEnd:null}}catch(e){}var n=S(f);Me(c.swapStyle,f,s,d,n);if(t.elt&&!ee(t.elt)&&t.elt.id){var r=document.getElementById(t.elt.id);var i={preventScroll:c.focusScroll!==undefined?!c.focusScroll:!z.config.defaultFocusScroll};if(r){if(t.start&&r.setSelectionRange){try{r.setSelectionRange(t.start,t.end)}catch(e){}}r.focus(i)}}f.classList.remove(z.config.swappingClass);Q(n.elts,function(e){if(e.classList){e.classList.add(z.config.settlingClass)}ie(e,"htmx:afterSwap",l)});if(E(u,/HX-Trigger-After-Swap:/i)){var a=s;if(!ee(s)){a=J().body}De(u,"HX-Trigger-After-Swap",a)}var o=function(){Q(n.tasks,function(e){e.call()});Q(n.elts,function(e){if(e.classList){e.classList.remove(z.config.settlingClass)}ie(e,"htmx:afterSettle",l)});if(h.type){if(h.type==="push"){Xt(h.path);ie(J().body,"htmx:pushedIntoHistory",{path:h.path})}else{Ft(h.path);ie(J().body,"htmx:replacedInHistory",{path:h.path})}}if(l.pathInfo.anchor){var e=b("#"+l.pathInfo.anchor);if(e){e.scrollIntoView({block:"start",behavior:"auto"})}}if(n.title){var t=b("title");if(t){t.innerHTML=n.title}else{window.document.title=n.title}}ar(n.elts,c);if(E(u,/HX-Trigger-After-Settle:/i)){var r=s;if(!ee(s)){r=J().body}De(u,"HX-Trigger-After-Settle",r)}K(v)};if(c.settleDelay>0){setTimeout(o,c.settleDelay)}else{o()}}catch(e){ne(s,"htmx:swapError",l);K(g);throw e}};var p=z.config.globalViewTransitions;if(c.hasOwnProperty("transition")){p=c.transition}if(p&&ie(s,"htmx:beforeTransition",l)&&typeof Promise!=="undefined"&&document.startViewTransition){var m=new Promise(function(e,t){v=e;g=t});var x=o;o=function(){document.startViewTransition(function(){x();return m})}}if(c.swapDelay>0){setTimeout(o,c.swapDelay)}else{o()}}if(n){ne(s,"htmx:responseError",te({error:"Response Status Error Code "+u.status+" from "+l.pathInfo.requestPath},l))}}var mr={};function xr(){return{init:function(e){return null},onEvent:function(e,t){return true},transformResponse:function(e,t,r){return e},isInlineSwap:function(e){return false},handleSwap:function(e,t,r,n){return false},encodeParameters:function(e,t,r){return null}}}function yr(e,t){if(t.init){t.init(C)}mr[e]=te(xr(),t)}function br(e){delete mr[e]}function wr(e,r,n){if(e==undefined){return r}if(r==undefined){r=[]}if(n==undefined){n=[]}var t=G(e,"hx-ext");if(t){Q(t.split(","),function(e){e=e.replace(/ /g,"");if(e.slice(0,7)=="ignore:"){n.push(e.slice(7));return}if(n.indexOf(e)<0){var t=mr[e];if(t&&r.indexOf(t)<0){r.push(t)}}})}return wr(u(e),r,n)}function Sr(e){if(J().readyState!=="loading"){e()}else{J().addEventListener("DOMContentLoaded",e)}}function Er(){if(z.config.includeIndicatorStyles!==false){J().head.insertAdjacentHTML("beforeend","")}}function Cr(){var e=J().querySelector('meta[name="htmx-config"]');if(e){return y(e.content)}else{return null}}function Rr(){var e=Cr();if(e){z.config=te(z.config,e)}}Sr(function(){Rr();Er();var e=J().body;Tt(e);var t=J().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(e){var t=e.target;var r=Y(t);if(r&&r.xhr){r.xhr.abort()}});var r=window.onpopstate;window.onpopstate=function(e){if(e.state&&e.state.htmx){Ut();Q(t,function(e){ie(e,"htmx:restored",{document:J(),triggerEvent:ie})})}else{if(r){r(e)}}};setTimeout(function(){ie(e,"htmx:load",{});e=null},0)});return z}()}); diff --git a/templ/examples/counter/cdk/.gitignore b/templ/examples/counter/cdk/.gitignore new file mode 100644 index 0000000..92fe1ec --- /dev/null +++ b/templ/examples/counter/cdk/.gitignore @@ -0,0 +1,19 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# go.sum should be committed +!go.sum + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/templ/examples/counter/cdk/cdk.json b/templ/examples/counter/cdk/cdk.json new file mode 100644 index 0000000..a53594c --- /dev/null +++ b/templ/examples/counter/cdk/cdk.json @@ -0,0 +1,47 @@ +{ + "app": "go mod download && go run stack.go", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "go.mod", + "go.sum", + "**/*test.go" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-iam:standardizedServicePrincipals": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true + } +} diff --git a/templ/examples/counter/cdk/stack.go b/templ/examples/counter/cdk/stack.go new file mode 100644 index 0000000..a253430 --- /dev/null +++ b/templ/examples/counter/cdk/stack.go @@ -0,0 +1,136 @@ +package main + +import ( + "fmt" + + "github.com/aws/aws-cdk-go/awscdk/v2" + "github.com/aws/aws-cdk-go/awscdk/v2/awscloudfront" + "github.com/aws/aws-cdk-go/awscdk/v2/awscloudfrontorigins" + "github.com/aws/aws-cdk-go/awscdk/v2/awsdynamodb" + "github.com/aws/aws-cdk-go/awscdk/v2/awsiam" + "github.com/aws/aws-cdk-go/awscdk/v2/awslambda" + "github.com/aws/aws-cdk-go/awscdk/v2/awss3" + "github.com/aws/aws-cdk-go/awscdk/v2/awss3deployment" + awslambdago "github.com/aws/aws-cdk-go/awscdklambdagoalpha/v2" + "github.com/aws/constructs-go/constructs/v10" + "github.com/aws/jsii-runtime-go" +) + +type CounterStackProps struct { + awscdk.StackProps +} + +func NewCounterStack(scope constructs.Construct, id string, props *CounterStackProps) awscdk.Stack { + var sprops awscdk.StackProps + if props != nil { + sprops = props.StackProps + } + stack := awscdk.NewStack(scope, &id, &sprops) + + // Create a global count database. + db := awsdynamodb.NewTable(stack, jsii.String("count"), &awsdynamodb.TableProps{ + PartitionKey: &awsdynamodb.Attribute{ + Name: jsii.String("_pk"), + Type: awsdynamodb.AttributeType_STRING, + }, + BillingMode: awsdynamodb.BillingMode_PAY_PER_REQUEST, + // Change this for production systems. + RemovalPolicy: awscdk.RemovalPolicy_DESTROY, + TimeToLiveAttribute: jsii.String("_ttl"), + }) + + // Strip the binary, and remove the deprecated Lambda SDK RPC code for performance. + // These options are not required, but make cold start faster. + bundlingOptions := &awslambdago.BundlingOptions{ + GoBuildFlags: &[]*string{jsii.String(`-ldflags "-s -w" -tags lambda.norpc`)}, + } + f := awslambdago.NewGoFunction(stack, jsii.String("handler"), &awslambdago.GoFunctionProps{ + Runtime: awslambda.Runtime_PROVIDED_AL2(), + MemorySize: jsii.Number(1024), + Architecture: awslambda.Architecture_ARM_64(), + Entry: jsii.String("../lambda"), + Bundling: bundlingOptions, + Environment: &map[string]*string{ + "TABLE_NAME": db.TableName(), + }, + }) + // Grant DB access. + db.GrantReadWriteData(f) + // Add a Function URL. + lambdaURL := f.AddFunctionUrl(&awslambda.FunctionUrlOptions{ + AuthType: awslambda.FunctionUrlAuthType_NONE, + }) + awscdk.NewCfnOutput(stack, jsii.String("lambdaFunctionUrl"), &awscdk.CfnOutputProps{ + ExportName: jsii.String("lambdaFunctionUrl"), + Value: lambdaURL.Url(), + }) + + assetsBucket := awss3.NewBucket(stack, jsii.String("assets"), &awss3.BucketProps{ + BlockPublicAccess: awss3.BlockPublicAccess_BLOCK_ALL(), + Encryption: awss3.BucketEncryption_S3_MANAGED, + EnforceSSL: jsii.Bool(true), + RemovalPolicy: awscdk.RemovalPolicy_DESTROY, + Versioned: jsii.Bool(false), + }) + // Allow CloudFront to read from the bucket. + cfOAI := awscloudfront.NewOriginAccessIdentity(stack, jsii.String("cfnOriginAccessIdentity"), &awscloudfront.OriginAccessIdentityProps{}) + cfs := awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{}) + cfs.AddActions(jsii.String("s3:GetBucket*")) + cfs.AddActions(jsii.String("s3:GetObject*")) + cfs.AddActions(jsii.String("s3:List*")) + cfs.AddResources(assetsBucket.BucketArn()) + cfs.AddResources(jsii.String(fmt.Sprintf("%v/*", *assetsBucket.BucketArn()))) + cfs.AddCanonicalUserPrincipal(cfOAI.CloudFrontOriginAccessIdentityS3CanonicalUserId()) + assetsBucket.AddToResourcePolicy(cfs) + + // Add a CloudFront distribution to route between the public directory and the Lambda function URL. + lambdaURLDomain := awscdk.Fn_Select(jsii.Number(2), awscdk.Fn_Split(jsii.String("/"), lambdaURL.Url(), nil)) + lambdaOrigin := awscloudfrontorigins.NewHttpOrigin(lambdaURLDomain, &awscloudfrontorigins.HttpOriginProps{ + ProtocolPolicy: awscloudfront.OriginProtocolPolicy_HTTPS_ONLY, + }) + cf := awscloudfront.NewDistribution(stack, jsii.String("customerFacing"), &awscloudfront.DistributionProps{ + DefaultBehavior: &awscloudfront.BehaviorOptions{ + AllowedMethods: awscloudfront.AllowedMethods_ALLOW_ALL(), + Origin: lambdaOrigin, + CachedMethods: awscloudfront.CachedMethods_CACHE_GET_HEAD(), + OriginRequestPolicy: awscloudfront.OriginRequestPolicy_ALL_VIEWER_EXCEPT_HOST_HEADER(), + CachePolicy: awscloudfront.CachePolicy_CACHING_DISABLED(), + ViewerProtocolPolicy: awscloudfront.ViewerProtocolPolicy_REDIRECT_TO_HTTPS, + }, + PriceClass: awscloudfront.PriceClass_PRICE_CLASS_100, + }) + + // Add /assets* to the distribution backed by S3. + assetsOrigin := awscloudfrontorigins.NewS3Origin(assetsBucket, &awscloudfrontorigins.S3OriginProps{ + // Get content from the / directory in the bucket. + OriginPath: jsii.String("/"), + OriginAccessIdentity: cfOAI, + }) + cf.AddBehavior(jsii.String("/assets*"), assetsOrigin, nil) + + // Export the domain. + awscdk.NewCfnOutput(stack, jsii.String("cloudFrontDomain"), &awscdk.CfnOutputProps{ + ExportName: jsii.String("cloudfrontDomain"), + Value: cf.DomainName(), + }) + + // Deploy the contents of the ./assets directory to the S3 bucket. + awss3deployment.NewBucketDeployment(stack, jsii.String("assetsDeployment"), &awss3deployment.BucketDeploymentProps{ + DestinationBucket: assetsBucket, + Sources: &[]awss3deployment.ISource{ + awss3deployment.Source_Asset(jsii.String("../assets"), nil), + }, + DestinationKeyPrefix: jsii.String("assets"), + Distribution: cf, + DistributionPaths: jsii.Strings("/assets*"), + }) + + return stack +} + +func main() { + defer jsii.Close() + app := awscdk.NewApp(nil) + NewCounterStack(app, "CounterStack", &CounterStackProps{}) + app.Synth(nil) +} diff --git a/templ/examples/counter/components/components.templ b/templ/examples/counter/components/components.templ new file mode 100644 index 0000000..39ccaa7 --- /dev/null +++ b/templ/examples/counter/components/components.templ @@ -0,0 +1,62 @@ +package components + +import "strconv" + +css border() { + border: 1px solid #eeeeee; + border-radius: 4px; + margin: 10px; + padding-top: 30px; + padding-bottom: 30px; +} + +templ counts(global, session int) { +
+
+
+

{ strconv.Itoa(global) }

+

Global

+
+
+
+

{ strconv.Itoa(session) }

+

Session

+
+
+
+
+} + +templ Page(global, session int) { + + + + + Counts + + + + + + + + +
+
+
+

Counts

+
+
+
+
+
+
+
+ @counts(global, session) +
+
+
+
+ + +} diff --git a/templ/examples/counter/components/components_templ.go b/templ/examples/counter/components/components_templ.go new file mode 100644 index 0000000..05ac8ea --- /dev/null +++ b/templ/examples/counter/components/components_templ.go @@ -0,0 +1,163 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "strconv" + +func border() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`border:1px solid #eeeeee;`) + templ_7745c5c3_CSSBuilder.WriteString(`border-radius:4px;`) + templ_7745c5c3_CSSBuilder.WriteString(`margin:10px;`) + templ_7745c5c3_CSSBuilder.WriteString(`padding-top:30px;`) + templ_7745c5c3_CSSBuilder.WriteString(`padding-bottom:30px;`) + templ_7745c5c3_CSSID := templ.CSSID(`border`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func counts(global, session int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 = []any{"column", "has-text-centered", "is-primary", border} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(global)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/counter/components/components.templ`, Line: 17, Col: 72} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

Global

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 = []any{"column", "has-text-centered", border} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(session)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/counter/components/components.templ`, Line: 22, Col: 73} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

Session

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Page(global, session int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "Counts

Counts

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = counts(global, session).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/counter/db/db.go b/templ/examples/counter/db/db.go new file mode 100644 index 0000000..2cbf3e8 --- /dev/null +++ b/templ/examples/counter/db/db.go @@ -0,0 +1,189 @@ +package db + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" +) + +type OptionsFunc func(*CountStore) + +func WithClient(client *dynamodb.Client) func(*CountStore) { + return func(ms *CountStore) { + ms.db = client + } +} + +func NewCountStore(tableName, region string, options ...OptionsFunc) (s *CountStore, err error) { + s = &CountStore{ + tableName: tableName, + } + for _, o := range options { + o(s) + } + if s.db == nil { + cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region)) + if err != nil { + return s, err + } + s.db = dynamodb.NewFromConfig(cfg) + } + return +} + +type CountStore struct { + db *dynamodb.Client + tableName string +} + +func stripEmpty(strings []string) (op []string) { + for _, s := range strings { + if s != "" { + op = append(op, s) + } + } + return +} + +type countRecord struct { + PK string `dynamodbav:"_pk"` + Count int `dynamodbav:"count"` +} + +func (s CountStore) BatchGet(ctx context.Context, ids ...string) (counts []int, err error) { + nonEmptyIDs := stripEmpty(ids) + if len(nonEmptyIDs) == 0 { + return nil, nil + } + + // Make DynamoDB keys. + ris := make(map[string]types.KeysAndAttributes) + for _, id := range nonEmptyIDs { + ri := ris[s.tableName] + ri.Keys = append(ris[s.tableName].Keys, map[string]types.AttributeValue{ + "_pk": &types.AttributeValueMemberS{ + Value: id, + }, + }) + ri.ConsistentRead = aws.Bool(true) + ris[s.tableName] = ri + } + + // Execute the batch request. + var batchResponses []map[string]types.AttributeValue + + // DynamoDB might not process everything, so we need a loop. + var unprocessedAttempts int + for { + var bgio *dynamodb.BatchGetItemOutput + bgio, err = s.db.BatchGetItem(ctx, &dynamodb.BatchGetItemInput{ + RequestItems: ris, + }) + if err != nil { + return + } + for _, responses := range bgio.Responses { + batchResponses = append(batchResponses, responses...) + } + if len(bgio.UnprocessedKeys) > 0 { + ris = bgio.UnprocessedKeys + unprocessedAttempts++ + if unprocessedAttempts > 3 { + err = fmt.Errorf("countstore: exceeded three attempts to get all counts") + return + } + continue + } + break + } + + // Process the responses into structs. + crs := []countRecord{} + err = attributevalue.UnmarshalListOfMaps(batchResponses, &crs) + if err != nil { + err = fmt.Errorf("countstore: failed to unmarshal result of BatchGet: %w", err) + return + } + + // Match up the inputs to the records. + idToCount := make(map[string]int, len(ids)) + for _, cr := range crs { + idToCount[cr.PK] = cr.Count + } + + // Create the output in the right order. + // Missing values are defaulted to zero. + for _, id := range ids { + counts = append(counts, idToCount[id]) + } + + return +} + +func (s CountStore) Get(ctx context.Context, id string) (count int, err error) { + if id == "" { + return + } + gio, err := s.db.GetItem(ctx, &dynamodb.GetItemInput{ + Key: map[string]types.AttributeValue{ + "_pk": &types.AttributeValueMemberS{ + Value: id, + }, + }, + TableName: &s.tableName, + ConsistentRead: aws.Bool(true), + }) + if err != nil || gio.Item == nil { + return + } + + var cr countRecord + err = attributevalue.UnmarshalMap(gio.Item, &cr) + if err != nil { + return 0, fmt.Errorf("countstore: failed to process result of Get: %w", err) + } + count = cr.Count + + return +} + +func (s CountStore) Increment(ctx context.Context, id string) (count int, err error) { + if id == "" { + return + } + uio, err := s.db.UpdateItem(ctx, &dynamodb.UpdateItemInput{ + Key: map[string]types.AttributeValue{ + "_pk": &types.AttributeValueMemberS{ + Value: id, + }, + }, + TableName: &s.tableName, + UpdateExpression: aws.String("SET #c = if_not_exists(#c, :zero) + :one"), + ExpressionAttributeNames: map[string]string{ + "#c": "count", + }, + ExpressionAttributeValues: map[string]types.AttributeValue{ + ":zero": &types.AttributeValueMemberN{Value: "0"}, + ":one": &types.AttributeValueMemberN{Value: "1"}, + }, + ReturnValues: types.ReturnValueAllNew, + }) + if err != nil { + return + } + + // Parse the response. + var cr countRecord + err = attributevalue.UnmarshalMap(uio.Attributes, &cr) + if err != nil { + return 0, fmt.Errorf("countstore: failed to process result of Increment: %w", err) + } + count = cr.Count + + return +} diff --git a/templ/examples/counter/go.mod b/templ/examples/counter/go.mod new file mode 100644 index 0000000..30bc1db --- /dev/null +++ b/templ/examples/counter/go.mod @@ -0,0 +1,53 @@ +module github.com/a-h/templ/examples/counter + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.234-0.20230427112944-80f0dc03a8a8 + github.com/akrylysov/algnhsa v1.1.0 + github.com/aws/aws-cdk-go/awscdk/v2 v2.147.3 + github.com/aws/aws-cdk-go/awscdklambdagoalpha/v2 v2.147.3-alpha.0 + github.com/aws/aws-sdk-go-v2 v1.30.1 + github.com/aws/aws-sdk-go-v2/config v1.27.24 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.7 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1 + github.com/aws/constructs-go/constructs/v10 v10.3.0 + github.com/aws/jsii-runtime-go v1.101.0 + github.com/segmentio/ksuid v1.0.4 + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 +) + +require ( + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/aws/aws-lambda-go v1.47.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.24 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.14 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect + github.com/aws/smithy-go v1.20.3 // indirect + github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.202 // indirect + github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.2 // indirect + github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.0.3 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/yuin/goldmark v1.7.4 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/tools v0.24.0 // indirect +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/counter/go.sum b/templ/examples/counter/go.sum new file mode 100644 index 0000000..fa17dff --- /dev/null +++ b/templ/examples/counter/go.sum @@ -0,0 +1,109 @@ +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/akrylysov/algnhsa v1.1.0 h1:G0SoP16tMRyiism7VNc3JFA0wq/cVgEkp/ExMVnc6PQ= +github.com/akrylysov/algnhsa v1.1.0/go.mod h1:+bOweRs/WBu5awl+ifCoSYAuKVPAmoTk8XOMrZ1xwiw= +github.com/aws/aws-cdk-go/awscdk/v2 v2.147.3 h1:7Wbi5d1f+RGn6fg9YzzMjD5D/rc/62zuFOtmJIed+B0= +github.com/aws/aws-cdk-go/awscdk/v2 v2.147.3/go.mod h1:WF3lt7ah4wNktbClICIBbKdITtCqyCrPBQl3nkaLug4= +github.com/aws/aws-cdk-go/awscdklambdagoalpha/v2 v2.147.3-alpha.0 h1:j+eT+oCMXTQZL+9ERI1FBDxkFApHPZTYZhtj9zalvlo= +github.com/aws/aws-cdk-go/awscdklambdagoalpha/v2 v2.147.3-alpha.0/go.mod h1:uUP2KJ0yXDOlAl5VmSN36cSpw5Ajv10JVhPl1M7WJ6A= +github.com/aws/aws-lambda-go v1.47.0 h1:0H8s0vumYx/YKs4sE7YM0ktwL2eWse+kfopsRI1sXVI= +github.com/aws/aws-lambda-go v1.47.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= +github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o= +github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2/config v1.27.24 h1:NM9XicZ5o1CBU/MZaHwFtimRpWx9ohAUAqkG6AqSqPo= +github.com/aws/aws-sdk-go-v2/config v1.27.24/go.mod h1:aXzi6QJTuQRVVusAO8/NxpdTeTyr/wRcybdDtfUwJSs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.24 h1:YclAsrnb1/GTQNt2nzv+756Iw4mF8AOzcDfweWwwm/M= +github.com/aws/aws-sdk-go-v2/credentials v1.17.24/go.mod h1:Hld7tmnAkoBQdTMNYZGzztzKRdA4fCdn9L83LOoigac= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.7 h1:pPhmvNKbgb9l5VHcPmMx9g+FHtRbY+ba2J6GefXQGEI= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.14.7/go.mod h1:OZU7QRvIYXhKry99PttkDTQyN8yCo8RzYjhIKHdQXoo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13/go.mod h1:i+kbfa76PQbWw/ULoWnp51EYVWH4ENln76fLQE3lXT8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1 h1:Szwz1vpZkvfhFMJ0X5uUECgHeUmPAxk1UGqAVs/pARw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.34.1/go.mod h1:b4wouGyJlzkr2HAvPrDGgYNp1EtmlXOkzhEOvl0c0FQ= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.1 h1:jfkCLx62YWL6bSOkT7aEDKNAX3OwWomlThCxQNBPvbY= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.22.1/go.mod h1:dLPiMfhRZhblwOeKqdNde7K9jl/pMuIGCGAwC6vQOIo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.14 h1:X1J0Kd17n1PeXeoArNXlvnKewCyMvhVQh7iNMy6oi3s= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.14/go.mod h1:VYMN7l7dxp6xtQRjqIau6d7QAbmPG+yJ75GtCy70f18= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 h1:I9zMeF107l0rJrpnHpjEiiTSCKYAIw8mALiXcPsGBiA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15/go.mod h1:9xWJ3Q/S6Ojusz1UIkfycgD1mGirJfLLKqq3LPT7WN8= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 h1:p1GahKIjyMDZtiKoIn0/jAj/TkMzfzndDv5+zi2Mhgc= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.1/go.mod h1:/vWdhoIoYA5hYoPZ6fm7Sv4d8701PiG5VKe8/pPJL60= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 h1:ORnrOK0C4WmYV/uYt3koHEWBLYsRDwk2Np+eEoyV4Z0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2/go.mod h1:xyFHA4zGxgYkdD73VeezHt3vSKEG9EmFnGwoKlP00u4= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.1/go.mod h1:jiNR3JqT15Dm+QWq2SRgh0x0bCNSRP2L25+CqPNpJlQ= +github.com/aws/constructs-go/constructs/v10 v10.3.0 h1:LsjBIMiaDX/vqrXWhzTquBJ9pPdi02/H+z1DCwg0PEM= +github.com/aws/constructs-go/constructs/v10 v10.3.0/go.mod h1:GgzwIwoRJ2UYsr3SU+JhAl+gq5j39bEMYf8ev3J+s9s= +github.com/aws/jsii-runtime-go v1.101.0 h1:x4rWNWRz7uDhVN0qSO7T6cG0VAhQ9300s5DjWUrXmWY= +github.com/aws/jsii-runtime-go v1.101.0/go.mod h1:4L4Qmve/HSwM5hXV5ZowR2gBNb9zqkUtycaaN6aZ3mg= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.202 h1:VixXB9DnHN8oP7pXipq8GVFPjWCOdeNxIaS/ZyUwTkI= +github.com/cdklabs/awscdk-asset-awscli-go/awscliv1/v2 v2.2.202/go.mod h1:iPUti/SWjA3XAS3CpnLciFjS8TN9Y+8mdZgDfSgcyus= +github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.2 h1:k+WD+6cERd59Mao84v0QtRrcdZuuSMfzlEmuIypKnVs= +github.com/cdklabs/awscdk-asset-kubectl-go/kubectlv20/v2 v2.1.2/go.mod h1:CvFHBo0qcg8LUkJqIxQtP1rD/sNGv9bX3L2vHT2FUAo= +github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.0.3 h1:8NLWOIVaxAtpUXv5reojlAeDP7R8yswm9mDONf7F/3o= +github.com/cdklabs/awscdk-asset-node-proxy-agent-go/nodeproxyagentv6/v2 v2.0.3/go.mod h1:ZjFqfhYpCLzh4z7ChcHCrkXfqCuEiRlNApDfJd6plts= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= +github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/templ/examples/counter/handlers/default.go b/templ/examples/counter/handlers/default.go new file mode 100644 index 0000000..6fc6fca --- /dev/null +++ b/templ/examples/counter/handlers/default.go @@ -0,0 +1,81 @@ +package handlers + +import ( + "context" + "net/http" + + "github.com/a-h/templ/examples/counter/components" + "github.com/a-h/templ/examples/counter/services" + "github.com/a-h/templ/examples/counter/session" + "golang.org/x/exp/slog" +) + +type CountService interface { + Increment(ctx context.Context, it services.IncrementType, sessionID string) (counts services.Counts, err error) + Get(ctx context.Context, sessionID string) (counts services.Counts, err error) +} + +func New(log *slog.Logger, cs CountService) *DefaultHandler { + return &DefaultHandler{ + Log: log, + CountService: cs, + } +} + +type DefaultHandler struct { + Log *slog.Logger + CountService CountService +} + +func (h *DefaultHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodPost { + h.Post(w, r) + return + } + h.Get(w, r) +} + +func (h *DefaultHandler) Get(w http.ResponseWriter, r *http.Request) { + var props ViewProps + var err error + props.Counts, err = h.CountService.Get(r.Context(), session.ID(r)) + if err != nil { + h.Log.Error("failed to get counts", slog.Any("error", err)) + http.Error(w, "failed to get counts", http.StatusInternalServerError) + return + } + h.View(w, r, props) +} + +func (h *DefaultHandler) Post(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + + // Decide the action to take based on the button that was pressed. + var it services.IncrementType + if r.Form.Has("global") { + it = services.IncrementTypeGlobal + } + if r.Form.Has("session") { + it = services.IncrementTypeSession + } + + counts, err := h.CountService.Increment(r.Context(), it, session.ID(r)) + if err != nil { + h.Log.Error("failed to increment", slog.Any("error", err)) + http.Error(w, "failed to increment", http.StatusInternalServerError) + return + } + + // Display the view. + h.View(w, r, ViewProps{ + Counts: counts, + }) +} + +type ViewProps struct { + Counts services.Counts +} + +func (h *DefaultHandler) View(w http.ResponseWriter, r *http.Request, props ViewProps) { + components.Page(props.Counts.Global, props.Counts.Session).Render(r.Context(), w) +} diff --git a/templ/examples/counter/lambda/main.go b/templ/examples/counter/lambda/main.go new file mode 100644 index 0000000..91cdc16 --- /dev/null +++ b/templ/examples/counter/lambda/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "os" + + "github.com/a-h/templ/examples/counter/db" + "github.com/a-h/templ/examples/counter/handlers" + "github.com/a-h/templ/examples/counter/services" + "github.com/a-h/templ/examples/counter/session" + "github.com/akrylysov/algnhsa" + "golang.org/x/exp/slog" +) + +func main() { + // Create handlers. + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) + if err != nil { + log.Error("failed to create store", slog.Any("error", err)) + os.Exit(1) + } + cs := services.NewCount(log, s) + h := handlers.New(log, cs) + + // Add session middleware. + sh := session.NewMiddleware(h) + + // Start Lambda. + algnhsa.ListenAndServe(sh, nil) +} diff --git a/templ/examples/counter/main.go b/templ/examples/counter/main.go new file mode 100644 index 0000000..f8140a4 --- /dev/null +++ b/templ/examples/counter/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "net/http" + "os" + "time" + + "github.com/a-h/templ/examples/counter/db" + "github.com/a-h/templ/examples/counter/handlers" + "github.com/a-h/templ/examples/counter/services" + "github.com/a-h/templ/examples/counter/session" + "golang.org/x/exp/slog" +) + +func main() { + log := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + s, err := db.NewCountStore(os.Getenv("TABLE_NAME"), os.Getenv("AWS_REGION")) + if err != nil { + log.Error("failed to create store", slog.Any("error", err)) + os.Exit(1) + } + cs := services.NewCount(log, s) + h := handlers.New(log, cs) + + var secureFlag = true + if os.Getenv("SECURE_FLAG") == "false" { + secureFlag = false + } + + // Add session middleware. + sh := session.NewMiddleware(h, session.WithSecure(secureFlag)) + + server := &http.Server{ + Addr: "localhost:9000", + Handler: sh, + ReadTimeout: time.Second * 10, + WriteTimeout: time.Second * 10, + } + + fmt.Printf("Listening on %v\n", server.Addr) + server.ListenAndServe() +} diff --git a/templ/examples/counter/services/count.go b/templ/examples/counter/services/count.go new file mode 100644 index 0000000..2501059 --- /dev/null +++ b/templ/examples/counter/services/count.go @@ -0,0 +1,84 @@ +package services + +import ( + "context" + "errors" + "fmt" + "sync" + + "github.com/a-h/templ/examples/counter/db" + "golang.org/x/exp/slog" +) + +type Counts struct { + Global int + Session int +} + +type IncrementType int + +const ( + IncrementTypeUnknown IncrementType = iota + IncrementTypeGlobal + IncrementTypeSession +) + +var ErrUnknownIncrementType error = errors.New("unknown increment type") + +func NewCount(log *slog.Logger, cs *db.CountStore) Count { + return Count{ + Log: log, + CountStore: cs, + } +} + +type Count struct { + Log *slog.Logger + CountStore *db.CountStore +} + +func (cs Count) Increment(ctx context.Context, it IncrementType, sessionID string) (counts Counts, err error) { + // Work out which operations to do. + var global, session func(ctx context.Context, id string) (count int, err error) + switch it { + case IncrementTypeGlobal: + global = cs.CountStore.Increment + session = cs.CountStore.Get + case IncrementTypeSession: + global = cs.CountStore.Get + session = cs.CountStore.Increment + default: + return counts, ErrUnknownIncrementType + } + + // Run the operations in parallel. + var wg sync.WaitGroup + wg.Add(2) + errs := make([]error, 2) + go func() { + defer wg.Done() + counts.Global, errs[0] = global(ctx, "global") + }() + go func() { + defer wg.Done() + counts.Session, errs[1] = session(ctx, sessionID) + }() + wg.Wait() + + return counts, errors.Join(errs...) +} + +func (cs Count) Get(ctx context.Context, sessionID string) (counts Counts, err error) { + globalAndSessionCounts, err := cs.CountStore.BatchGet(ctx, "global", sessionID) + if err != nil { + err = fmt.Errorf("countservice: failed to get counts: %w", err) + return + } + if len(globalAndSessionCounts) != 2 { + err = fmt.Errorf("countservice: unexpected counts returned, expected 2, got %d", len(globalAndSessionCounts)) + return + } + counts.Global = globalAndSessionCounts[0] + counts.Session = globalAndSessionCounts[1] + return +} diff --git a/templ/examples/counter/session/session.go b/templ/examples/counter/session/session.go new file mode 100644 index 0000000..43d9b14 --- /dev/null +++ b/templ/examples/counter/session/session.go @@ -0,0 +1,56 @@ +package session + +import ( + "net/http" + + "github.com/segmentio/ksuid" +) + +type MiddlewareOpts func(*Middleware) + +func NewMiddleware(next http.Handler, opts ...MiddlewareOpts) http.Handler { + mw := Middleware{ + Next: next, + Secure: true, + HTTPOnly: true, + } + for _, opt := range opts { + opt(&mw) + } + return mw +} + +func WithSecure(secure bool) MiddlewareOpts { + return func(m *Middleware) { + m.Secure = secure + } +} + +func WithHTTPOnly(httpOnly bool) MiddlewareOpts { + return func(m *Middleware) { + m.HTTPOnly = httpOnly + } +} + +type Middleware struct { + Next http.Handler + Secure bool + HTTPOnly bool +} + +func ID(r *http.Request) (id string) { + cookie, err := r.Cookie("sessionID") + if err != nil { + return + } + return cookie.Value +} + +func (mw Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + id := ID(r) + if id == "" { + id = ksuid.New().String() + http.SetCookie(w, &http.Cookie{Name: "sessionID", Value: id, Secure: mw.Secure, HttpOnly: mw.HTTPOnly}) + } + mw.Next.ServeHTTP(w, r) +} diff --git a/templ/examples/external-libraries/components.templ b/templ/examples/external-libraries/components.templ new file mode 100644 index 0000000..794ae0f --- /dev/null +++ b/templ/examples/external-libraries/components.templ @@ -0,0 +1,19 @@ +package main + +script graph(data []TimeValue) { + const chart = LightweightCharts.createChart(document.body, { width: 400, height: 300 }); + const lineSeries = chart.addLineSeries(); + lineSeries.setData(data); +} + +templ page(data []TimeValue) { + + + + + Graphs + + + + +} diff --git a/templ/examples/external-libraries/components_templ.go b/templ/examples/external-libraries/components_templ.go new file mode 100644 index 0000000..6747f1d --- /dev/null +++ b/templ/examples/external-libraries/components_templ.go @@ -0,0 +1,69 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func graph(data []TimeValue) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_graph_c2ba`, + Function: `function __templ_graph_c2ba(data){const chart = LightweightCharts.createChart(document.body, { width: 400, height: 300 }); + const lineSeries = chart.addLineSeries(); + lineSeries.setData(data); +}`, + Call: templ.SafeScript(`__templ_graph_c2ba`, data), + CallInline: templ.SafeScriptInline(`__templ_graph_c2ba`, data), + } +} + +func page(data []TimeValue) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Graphs") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, graph(data)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/external-libraries/go.mod b/templ/examples/external-libraries/go.mod new file mode 100644 index 0000000..60e60f6 --- /dev/null +++ b/templ/examples/external-libraries/go.mod @@ -0,0 +1,9 @@ +module github.com/a-h/templ/examples/external-libraries + +go 1.23 + +toolchain go1.23.3 + +require github.com/a-h/templ v0.2.304 + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/external-libraries/go.sum b/templ/examples/external-libraries/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/examples/external-libraries/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/external-libraries/main.go b/templ/examples/external-libraries/main.go new file mode 100644 index 0000000..159e9f1 --- /dev/null +++ b/templ/examples/external-libraries/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "log" + "net/http" +) + +type TimeValue struct { + Time string `json:"time"` + Value float64 `json:"value"` +} + +func main() { + mux := http.NewServeMux() + + // Handle template. + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + data := []TimeValue{ + {Time: "2019-04-11", Value: 80.01}, + {Time: "2019-04-12", Value: 96.63}, + {Time: "2019-04-13", Value: 76.64}, + {Time: "2019-04-14", Value: 81.89}, + {Time: "2019-04-15", Value: 74.43}, + {Time: "2019-04-16", Value: 80.01}, + {Time: "2019-04-17", Value: 96.63}, + {Time: "2019-04-18", Value: 76.64}, + {Time: "2019-04-19", Value: 81.89}, + {Time: "2019-04-20", Value: 74.43}, + } + page(data).Render(r.Context(), w) + }) + + // Start the server. + fmt.Println("listening on :8080") + if err := http.ListenAndServe(":8080", mux); err != nil { + log.Printf("error listening: %v", err) + } +} diff --git a/templ/examples/hello-world-ssr/hello.templ b/templ/examples/hello-world-ssr/hello.templ new file mode 100644 index 0000000..6f1786f --- /dev/null +++ b/templ/examples/hello-world-ssr/hello.templ @@ -0,0 +1,5 @@ +package main + +templ hello(name string) { +
Hello, { name }
+} diff --git a/templ/examples/hello-world-ssr/hello_templ.go b/templ/examples/hello-world-ssr/hello_templ.go new file mode 100644 index 0000000..8379b3a --- /dev/null +++ b/templ/examples/hello-world-ssr/hello_templ.go @@ -0,0 +1,53 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func hello(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello, ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/hello-world-ssr/hello.templ`, Line: 4, Col: 19} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/hello-world-ssr/main.go b/templ/examples/hello-world-ssr/main.go new file mode 100644 index 0000000..d60ec66 --- /dev/null +++ b/templ/examples/hello-world-ssr/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/a-h/templ" +) + +func main() { + component := hello("John") + + http.Handle("/", templ.Handler(component)) + + fmt.Println("Listening on :3000") + http.ListenAndServe(":3000", nil) +} diff --git a/templ/examples/hello-world-static/hello.templ b/templ/examples/hello-world-static/hello.templ new file mode 100644 index 0000000..6f1786f --- /dev/null +++ b/templ/examples/hello-world-static/hello.templ @@ -0,0 +1,5 @@ +package main + +templ hello(name string) { +
Hello, { name }
+} diff --git a/templ/examples/hello-world-static/hello_templ.go b/templ/examples/hello-world-static/hello_templ.go new file mode 100644 index 0000000..94ca408 --- /dev/null +++ b/templ/examples/hello-world-static/hello_templ.go @@ -0,0 +1,53 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func hello(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello, ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/hello-world-static/hello.templ`, Line: 4, Col: 19} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/hello-world-static/main.go b/templ/examples/hello-world-static/main.go new file mode 100644 index 0000000..a3b29a1 --- /dev/null +++ b/templ/examples/hello-world-static/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "context" + "os" +) + +func main() { + component := hello("John") + component.Render(context.Background(), os.Stdout) +} diff --git a/templ/examples/integration-chi/go.mod b/templ/examples/integration-chi/go.mod new file mode 100644 index 0000000..d570381 --- /dev/null +++ b/templ/examples/integration-chi/go.mod @@ -0,0 +1,12 @@ +module github.com/a-h/templ/examples/integration-chi + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.364 + github.com/go-chi/chi/v5 v5.2.0 +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-chi/go.sum b/templ/examples/integration-chi/go.sum new file mode 100644 index 0000000..15d0bab --- /dev/null +++ b/templ/examples/integration-chi/go.sum @@ -0,0 +1,4 @@ +github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= +github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/integration-chi/home.templ b/templ/examples/integration-chi/home.templ new file mode 100644 index 0000000..7444b11 --- /dev/null +++ b/templ/examples/integration-chi/home.templ @@ -0,0 +1,5 @@ +package main + +templ Home() { +
Hello World
+} diff --git a/templ/examples/integration-chi/home_templ.go b/templ/examples/integration-chi/home_templ.go new file mode 100644 index 0000000..8b7d55a --- /dev/null +++ b/templ/examples/integration-chi/home_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Home() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello World
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-chi/main.go b/templ/examples/integration-chi/main.go new file mode 100644 index 0000000..d18f8da --- /dev/null +++ b/templ/examples/integration-chi/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "net/http" + + "github.com/a-h/templ" + "github.com/go-chi/chi/v5" +) + +func main() { + r := chi.NewRouter() + r.Get("/", templ.Handler(Home()).ServeHTTP) + http.ListenAndServe(":3000", r) +} diff --git a/templ/examples/integration-echo/go.mod b/templ/examples/integration-echo/go.mod new file mode 100644 index 0000000..c52d07d --- /dev/null +++ b/templ/examples/integration-echo/go.mod @@ -0,0 +1,24 @@ +module github.com/a-h/templ/examples/integration-echo + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.663 + github.com/labstack/echo/v4 v4.13.3 +) + +require ( + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-echo/go.sum b/templ/examples/integration-echo/go.sum new file mode 100644 index 0000000..93fd900 --- /dev/null +++ b/templ/examples/integration-echo/go.sum @@ -0,0 +1,33 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= +github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/templ/examples/integration-echo/home.templ b/templ/examples/integration-echo/home.templ new file mode 100644 index 0000000..7444b11 --- /dev/null +++ b/templ/examples/integration-echo/home.templ @@ -0,0 +1,5 @@ +package main + +templ Home() { +
Hello World
+} diff --git a/templ/examples/integration-echo/home_templ.go b/templ/examples/integration-echo/home_templ.go new file mode 100644 index 0000000..8b7d55a --- /dev/null +++ b/templ/examples/integration-echo/home_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Home() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello World
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-echo/main.go b/templ/examples/integration-echo/main.go new file mode 100644 index 0000000..144d3c5 --- /dev/null +++ b/templ/examples/integration-echo/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "net/http" + + "github.com/a-h/templ" + "github.com/labstack/echo/v4" +) + +func main() { + app := echo.New() + app.GET("/", HomeHandler) + app.Logger.Fatal(app.Start(":4000")) +} + +// This custom Render replaces Echo's echo.Context.Render() with templ's templ.Component.Render(). +func Render(ctx echo.Context, statusCode int, t templ.Component) error { + buf := templ.GetBuffer() + defer templ.ReleaseBuffer(buf) + + if err := t.Render(ctx.Request().Context(), buf); err != nil { + return err + } + + return ctx.HTML(statusCode, buf.String()) +} + +func HomeHandler(c echo.Context) error { + return Render(c, http.StatusOK, Home()) +} diff --git a/templ/examples/integration-gin/gintemplrenderer/renderer.go b/templ/examples/integration-gin/gintemplrenderer/renderer.go new file mode 100644 index 0000000..4020d3a --- /dev/null +++ b/templ/examples/integration-gin/gintemplrenderer/renderer.go @@ -0,0 +1,58 @@ +package gintemplrenderer + +import ( + "context" + "github.com/gin-gonic/gin/render" + "net/http" + + "github.com/a-h/templ" +) + +var Default = &HTMLTemplRenderer{} + +type HTMLTemplRenderer struct { + FallbackHtmlRenderer render.HTMLRender +} + +func (r *HTMLTemplRenderer) Instance(s string, d any) render.Render { + templData, ok := d.(templ.Component) + if !ok { + if r.FallbackHtmlRenderer != nil { + return r.FallbackHtmlRenderer.Instance(s, d) + } + } + return &Renderer{ + Ctx: context.Background(), + Status: -1, + Component: templData, + } +} + +func New(ctx context.Context, status int, component templ.Component) *Renderer { + return &Renderer{ + Ctx: ctx, + Status: status, + Component: component, + } +} + +type Renderer struct { + Ctx context.Context + Status int + Component templ.Component +} + +func (t Renderer) Render(w http.ResponseWriter) error { + t.WriteContentType(w) + if t.Status != -1 { + w.WriteHeader(t.Status) + } + if t.Component != nil { + return t.Component.Render(t.Ctx, w) + } + return nil +} + +func (t Renderer) WriteContentType(w http.ResponseWriter) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") +} diff --git a/templ/examples/integration-gin/go.mod b/templ/examples/integration-gin/go.mod new file mode 100644 index 0000000..864e5c6 --- /dev/null +++ b/templ/examples/integration-gin/go.mod @@ -0,0 +1,52 @@ +module github.com/a-h/templ/examples/integration-gin + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.663 + github.com/gin-gonic/gin v1.10.1-0.20241230033924-23d6961aeb9d +) + +require ( + github.com/bytedance/sonic v1.12.6 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/goccy/go-json v0.10.4 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.48.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + go.uber.org/mock v0.5.0 // indirect + golang.org/x/arch v0.12.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.28.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-gin/go.sum b/templ/examples/integration-gin/go.sum new file mode 100644 index 0000000..2b0d1c4 --- /dev/null +++ b/templ/examples/integration-gin/go.sum @@ -0,0 +1,142 @@ +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= +github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= +github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/gin-gonic/gin v1.10.1-0.20241230033924-23d6961aeb9d h1:3+s8/96EWhqfcjxziXIe21i1IiVyclOZddVVSUCcgVI= +github.com/gin-gonic/gin v1.10.1-0.20241230033924-23d6961aeb9d/go.mod h1:n9YAH8YJcBQ0JmhP43dOtzM7D/2lv0joQZ+lgI67Bdw= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= +github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= +golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/templ/examples/integration-gin/home.html b/templ/examples/integration-gin/home.html new file mode 100644 index 0000000..52ea02c --- /dev/null +++ b/templ/examples/integration-gin/home.html @@ -0,0 +1 @@ +
Hello world
diff --git a/templ/examples/integration-gin/home.templ b/templ/examples/integration-gin/home.templ new file mode 100644 index 0000000..8ee27f1 --- /dev/null +++ b/templ/examples/integration-gin/home.templ @@ -0,0 +1,5 @@ +package main + +templ Home() { +
Hello world
+} diff --git a/templ/examples/integration-gin/home_templ.go b/templ/examples/integration-gin/home_templ.go new file mode 100644 index 0000000..183765e --- /dev/null +++ b/templ/examples/integration-gin/home_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Home() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello world
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-gin/main.go b/templ/examples/integration-gin/main.go new file mode 100644 index 0000000..7d14b74 --- /dev/null +++ b/templ/examples/integration-gin/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "net/http" + + "github.com/a-h/templ/examples/integration-gin/gintemplrenderer" + "github.com/gin-gonic/gin" +) + +func main() { + engine := gin.Default() + engine.LoadHTMLFiles("./home.html") + + //engine.HTMLRender = gintemplrenderer.Default + + ginHtmlRenderer := engine.HTMLRender + engine.HTMLRender = &gintemplrenderer.HTMLTemplRenderer{FallbackHtmlRenderer: ginHtmlRenderer} + + // Disable trusted proxy warning. + engine.SetTrustedProxies(nil) + + engine.GET("/", func(c *gin.Context) { + c.HTML(http.StatusOK, "", Home()) + }) + + engine.GET("/with-ctx", func(c *gin.Context) { + r := gintemplrenderer.New(c.Request.Context(), http.StatusOK, Home()) + c.Render(http.StatusOK, r) + }) + + engine.GET("/with-fallback-renderer", func(c *gin.Context) { + c.HTML(http.StatusOK, "home.html", gin.H{}) + }) + + engine.Run(":8080") +} diff --git a/templ/examples/integration-go-echarts/components.templ b/templ/examples/integration-go-echarts/components.templ new file mode 100644 index 0000000..7cd279a --- /dev/null +++ b/templ/examples/integration-go-echarts/components.templ @@ -0,0 +1,14 @@ +package main + +import "github.com/go-echarts/go-echarts/v2/charts" + +templ Home(chart *charts.Bar) { + + + Bar chart + + + @ConvertChartToTemplComponent(chart) + + +} diff --git a/templ/examples/integration-go-echarts/components_templ.go b/templ/examples/integration-go-echarts/components_templ.go new file mode 100644 index 0000000..52198d3 --- /dev/null +++ b/templ/examples/integration-go-echarts/components_templ.go @@ -0,0 +1,50 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "github.com/go-echarts/go-echarts/v2/charts" + +func Home(chart *charts.Bar) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Bar chart") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ConvertChartToTemplComponent(chart).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-go-echarts/go.mod b/templ/examples/integration-go-echarts/go.mod new file mode 100644 index 0000000..f79c6f3 --- /dev/null +++ b/templ/examples/integration-go-echarts/go.mod @@ -0,0 +1,12 @@ +module github.com/a-h/templ/examples/integration-go-echarts + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.529 + github.com/go-echarts/go-echarts/v2 v2.4.0 +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-go-echarts/go.sum b/templ/examples/integration-go-echarts/go.sum new file mode 100644 index 0000000..cd25d1a --- /dev/null +++ b/templ/examples/integration-go-echarts/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-echarts/go-echarts/v2 v2.4.0 h1:efD46dmAvaZEWrBHAGjE8cfDK48vvFTHz5N9VqW5rYc= +github.com/go-echarts/go-echarts/v2 v2.4.0/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/templ/examples/integration-go-echarts/main.go b/templ/examples/integration-go-echarts/main.go new file mode 100644 index 0000000..5d2fb4f --- /dev/null +++ b/templ/examples/integration-go-echarts/main.go @@ -0,0 +1,54 @@ +package main + +import ( + "context" + "io" + "math/rand" + "net/http" + + "github.com/a-h/templ" + "github.com/go-echarts/go-echarts/v2/charts" + "github.com/go-echarts/go-echarts/v2/opts" +) + +func generateBarItems() []opts.BarData { + items := make([]opts.BarData, 0) + for i := 0; i < 7; i++ { + items = append(items, opts.BarData{Value: rand.Intn(300)}) + } + return items +} + +func createBarChart() *charts.Bar { + bar := charts.NewBar() + bar.SetGlobalOptions(charts.WithTitleOpts(opts.Title{ + Title: "Bar chart", + Subtitle: "That works well with templ", + })) + bar.SetXAxis([]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}). + AddSeries("Category A", generateBarItems()). + AddSeries("Category B", generateBarItems()) + return bar +} + +// The charts all have a `Render(w io.Writer) error` method on them. +// That method is very similar to templ's Render method. +type Renderable interface { + Render(w io.Writer) error +} + +// So lets adapt it. +func ConvertChartToTemplComponent(chart Renderable) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + return chart.Render(w) + }) +} + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + chart := createBarChart() + h := templ.Handler(Home(chart)) + h.ServeHTTP(w, r) + }) + http.ListenAndServe("localhost:3000", nil) +} diff --git a/templ/examples/integration-gofiber/README.md b/templ/examples/integration-gofiber/README.md new file mode 100644 index 0000000..1271139 --- /dev/null +++ b/templ/examples/integration-gofiber/README.md @@ -0,0 +1,24 @@ +## Example + +This example demonstrates the usage of templ with gofiber. + +As soon as you start the server you can access http://localhost:3000/ and see the rendered page. + +If you change the URL to http://localhost:3000/john you will see your parameter printed on the page. + +This happens both through parameter passing into the templ component and through context using fiber locals. + +## Tasks + +### build-templ + +``` +templ generate +``` + +### run + +``` +go run . +``` + diff --git a/templ/examples/integration-gofiber/go.mod b/templ/examples/integration-gofiber/go.mod new file mode 100644 index 0000000..af59fd2 --- /dev/null +++ b/templ/examples/integration-gofiber/go.mod @@ -0,0 +1,26 @@ +module github.com/a-h/templ/examples/integration-gofiber + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.747 + github.com/gofiber/fiber/v2 v2.52.5 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.55.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/sys v0.28.0 // indirect +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-gofiber/go.sum b/templ/examples/integration-gofiber/go.sum new file mode 100644 index 0000000..c64a94a --- /dev/null +++ b/templ/examples/integration-gofiber/go.sum @@ -0,0 +1,30 @@ +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/templ/examples/integration-gofiber/home.templ b/templ/examples/integration-gofiber/home.templ new file mode 100644 index 0000000..d36b7ce --- /dev/null +++ b/templ/examples/integration-gofiber/home.templ @@ -0,0 +1,19 @@ +package main + +import "context" + +func NameFromContext(ctx context.Context) string { + if name, ok := ctx.Value("name").(string); ok && name != "" { + return name + } + return "World" +} + +templ Home(name string) { +
Hello { name }
+
Hello { NameFromContext(ctx) } (from context)
+} + +templ NotFound() { +
404
+} diff --git a/templ/examples/integration-gofiber/home_templ.go b/templ/examples/integration-gofiber/home_templ.go new file mode 100644 index 0000000..564fb75 --- /dev/null +++ b/templ/examples/integration-gofiber/home_templ.go @@ -0,0 +1,104 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "context" + +func NameFromContext(ctx context.Context) string { + if name, ok := ctx.Value("name").(string); ok && name != "" { + return name + } + return "World" +} + +func Home(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Hello ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/integration-gofiber/home.templ`, Line: 13, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
Hello ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(NameFromContext(ctx)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/integration-gofiber/home.templ`, Line: 14, Col: 34} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " (from context)
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func NotFound() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
404
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-gofiber/main.go b/templ/examples/integration-gofiber/main.go new file mode 100644 index 0000000..c663496 --- /dev/null +++ b/templ/examples/integration-gofiber/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "github.com/a-h/templ" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" +) + +func main() { + app := fiber.New() + + app.Get("/:name?", func(c *fiber.Ctx) error { + name := c.Params("name") + c.Locals("name", name) + if name == "" { + name = "World" + } + return Render(c, Home(name)) + }) + app.Use(NotFoundMiddleware) + + log.Fatal(app.Listen(":3000")) +} + +func NotFoundMiddleware(c *fiber.Ctx) error { + c.Status(fiber.StatusNotFound) + return Render(c, NotFound()) +} + +func Render(c *fiber.Ctx, component templ.Component) error { + c.Set("Content-Type", "text/html") + return component.Render(c.Context(), c.Response().BodyWriter()) +} diff --git a/templ/examples/integration-react/README.md b/templ/examples/integration-react/README.md new file mode 100644 index 0000000..92e05eb --- /dev/null +++ b/templ/examples/integration-react/README.md @@ -0,0 +1,31 @@ +## Tasks + +### build-templ + +``` +templ generate +``` + +### build-js + +Dir: react + +``` +esbuild --bundle index.ts --outdir=../static --minify --global-name=bundle +``` + +### run + +``` +go run . +``` + +### all + +Requires: build-templ +Requires: build-js +Requires: run + +``` +echo "Running" +``` diff --git a/templ/examples/integration-react/components.templ b/templ/examples/integration-react/components.templ new file mode 100644 index 0000000..54a7aa1 --- /dev/null +++ b/templ/examples/integration-react/components.templ @@ -0,0 +1,33 @@ +package main + +templ Hello(name string) { +
+ +
+} + +templ page() { + + + React integration + + +
+
+
+ This is server-side content from templ. +
+ + + + + + for _, name := range []string{"Alice", "Bob", "Charlie"} { + @Hello(name) + } + + +} diff --git a/templ/examples/integration-react/components_templ.go b/templ/examples/integration-react/components_templ.go new file mode 100644 index 0000000..52d3387 --- /dev/null +++ b/templ/examples/integration-react/components_templ.go @@ -0,0 +1,92 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Hello(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func page() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "React integration
This is server-side content from templ.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, name := range []string{"Alice", "Bob", "Charlie"} { + templ_7745c5c3_Err = Hello(name).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/integration-react/flake.lock b/templ/examples/integration-react/flake.lock new file mode 100644 index 0000000..e994a05 --- /dev/null +++ b/templ/examples/integration-react/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1701282334, + "narHash": "sha256-MxCVrXY6v4QmfTwIysjjaX0XUhqBbxTWWB4HXtDYsdk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "057f9aecfb71c4437d2b27d3323df7f93c010b7e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/templ/examples/integration-react/flake.nix b/templ/examples/integration-react/flake.nix new file mode 100644 index 0000000..3a54d3a --- /dev/null +++ b/templ/examples/integration-react/flake.nix @@ -0,0 +1,34 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/23.11"; + }; + + # Flake outputs + outputs = { self, nixpkgs }: + let + # Systems supported + allSystems = [ + "x86_64-linux" # 64-bit Intel/AMD Linux + "aarch64-linux" # 64-bit ARM Linux + "x86_64-darwin" # 64-bit Intel macOS + "aarch64-darwin" # 64-bit ARM macOS + ]; + + # Helper to provide system-specific attributes + forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { + pkgs = import nixpkgs { inherit system; }; + }); + in + { + # Development environment output + devShells = forAllSystems ({ pkgs }: { + default = pkgs.mkShell { + # The Nix packages provided in the environment + packages = with pkgs; [ + nodejs_18 # Node.js 18, plus npm, npx, and corepack + esbuild + ]; + }; + }); + }; +} diff --git a/templ/examples/integration-react/go.mod b/templ/examples/integration-react/go.mod new file mode 100644 index 0000000..37941a7 --- /dev/null +++ b/templ/examples/integration-react/go.mod @@ -0,0 +1,9 @@ +module github.com/a-h/templ/examples/integration-react + +go 1.23 + +toolchain go1.23.3 + +require github.com/a-h/templ v0.2.513 + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/integration-react/go.sum b/templ/examples/integration-react/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/examples/integration-react/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/integration-react/main.go b/templ/examples/integration-react/main.go new file mode 100644 index 0000000..c37d196 --- /dev/null +++ b/templ/examples/integration-react/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "log" + "net/http" + + "github.com/a-h/templ" +) + +func main() { + mux := http.NewServeMux() + + // Serve the templ page. + mux.Handle("/", templ.Handler(page())) + + // Serve static content. + mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) + + // Start the server. + fmt.Println("listening on localhost:8080") + if err := http.ListenAndServe("localhost:8080", mux); err != nil { + log.Printf("error listening: %v", err) + } +} diff --git a/templ/examples/integration-react/react/.gitignore b/templ/examples/integration-react/react/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/templ/examples/integration-react/react/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/templ/examples/integration-react/react/components.tsx b/templ/examples/integration-react/react/components.tsx new file mode 100644 index 0000000..327562b --- /dev/null +++ b/templ/examples/integration-react/react/components.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +export const Header = () => (

React component Header

); + +export const Body = () => (
This is client-side content from React
); + +export const Hello = (name: string) => (
Hello {name} (Client-side React, rendering server-side data)
); diff --git a/templ/examples/integration-react/react/index.ts b/templ/examples/integration-react/react/index.ts new file mode 100644 index 0000000..20f86a5 --- /dev/null +++ b/templ/examples/integration-react/react/index.ts @@ -0,0 +1,24 @@ +import { createRoot } from 'react-dom/client'; +import { Header, Body, Hello } from './components'; + +// Render the React component into the templ page at the react-header. +const headerRoot = document.getElementById('react-header'); +if (!headerRoot) { + throw new Error('Could not find element with id react-header'); +} +const headerReactRoot = createRoot(headerRoot); +headerReactRoot.render(Header()); + +// Add the body React component. +const contentRoot = document.getElementById('react-content'); +if (!contentRoot) { + throw new Error('Could not find element with id react-content'); +} +const contentReactRoot = createRoot(contentRoot); +contentReactRoot.render(Body()); + +// Provide a helper for rendering hello. +export function renderHello(e: HTMLElement) { + const name = e.getAttribute('data-name') ?? ""; + createRoot(e).render(Hello(name)); +} diff --git a/templ/examples/integration-react/react/package-lock.json b/templ/examples/integration-react/react/package-lock.json new file mode 100644 index 0000000..320a3c6 --- /dev/null +++ b/templ/examples/integration-react/react/package-lock.json @@ -0,0 +1,119 @@ +{ + "name": "integration-react", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "integration-react", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react-dom": "^18.2.18", + "typescript": "^5.3.3" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.2.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.47.tgz", + "integrity": "sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/templ/examples/integration-react/react/package.json b/templ/examples/integration-react/react/package.json new file mode 100644 index 0000000..592970a --- /dev/null +++ b/templ/examples/integration-react/react/package.json @@ -0,0 +1,19 @@ +{ + "name": "integration-react", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react-dom": "^18.2.18", + "typescript": "^5.3.3" + } +} diff --git a/templ/examples/integration-react/react/tsconfig.json b/templ/examples/integration-react/react/tsconfig.json new file mode 100644 index 0000000..a224293 --- /dev/null +++ b/templ/examples/integration-react/react/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsx": "react-jsx" + } +} diff --git a/templ/examples/integration-react/static/index.js b/templ/examples/integration-react/static/index.js new file mode 100644 index 0000000..014658a --- /dev/null +++ b/templ/examples/integration-react/static/index.js @@ -0,0 +1,54 @@ +var bundle=(()=>{var Ac=Object.create;var nr=Object.defineProperty;var Hc=Object.getOwnPropertyDescriptor;var Bc=Object.getOwnPropertyNames;var Wc=Object.getPrototypeOf,$c=Object.prototype.hasOwnProperty;var je=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports),Qc=(e,n)=>{for(var t in n)nr(e,t,{get:n[t],enumerable:!0})},Gu=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let l of Bc(n))!$c.call(e,l)&&l!==t&&nr(e,l,{get:()=>n[l],enumerable:!(r=Hc(n,l))||r.enumerable});return e};var Nl=(e,n,t)=>(t=e!=null?Ac(Wc(e)):{},Gu(n||!e||!e.__esModule?nr(t,"default",{value:e,enumerable:!0}):t,e)),Kc=e=>Gu(nr({},"__esModule",{value:!0}),e);var ui=je(N=>{"use strict";var st=Symbol.for("react.element"),Yc=Symbol.for("react.portal"),Xc=Symbol.for("react.fragment"),Gc=Symbol.for("react.strict_mode"),Zc=Symbol.for("react.profiler"),Jc=Symbol.for("react.provider"),qc=Symbol.for("react.context"),bc=Symbol.for("react.forward_ref"),ef=Symbol.for("react.suspense"),nf=Symbol.for("react.memo"),tf=Symbol.for("react.lazy"),Zu=Symbol.iterator;function rf(e){return e===null||typeof e!="object"?null:(e=Zu&&e[Zu]||e["@@iterator"],typeof e=="function"?e:null)}var bu={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ei=Object.assign,ni={};function On(e,n,t){this.props=e,this.context=n,this.refs=ni,this.updater=t||bu}On.prototype.isReactComponent={};On.prototype.setState=function(e,n){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,n,"setState")};On.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function ti(){}ti.prototype=On.prototype;function zl(e,n,t){this.props=e,this.context=n,this.refs=ni,this.updater=t||bu}var Tl=zl.prototype=new ti;Tl.constructor=zl;ei(Tl,On.prototype);Tl.isPureReactComponent=!0;var Ju=Array.isArray,ri=Object.prototype.hasOwnProperty,Ll={current:null},li={key:!0,ref:!0,__self:!0,__source:!0};function oi(e,n,t){var r,l={},o=null,u=null;if(n!=null)for(r in n.ref!==void 0&&(u=n.ref),n.key!==void 0&&(o=""+n.key),n)ri.call(n,r)&&!li.hasOwnProperty(r)&&(l[r]=n[r]);var i=arguments.length-2;if(i===1)l.children=t;else if(1{"use strict";ii.exports=ui()});var yi=je(L=>{"use strict";function Fl(e,n){var t=e.length;e.push(n);e:for(;0>>1,l=e[r];if(0>>1;ror(i,t))sor(f,i)?(e[r]=f,e[s]=t,r=s):(e[r]=i,e[u]=t,r=u);else if(sor(f,t))e[r]=f,e[s]=t,r=s;else break e}}return n}function or(e,n){var t=e.sortIndex-n.sortIndex;return t!==0?t:e.id-n.id}typeof performance=="object"&&typeof performance.now=="function"?(si=performance,L.unstable_now=function(){return si.now()}):(Dl=Date,ai=Dl.now(),L.unstable_now=function(){return Dl.now()-ai});var si,Dl,ai,Re=[],Ge=[],af=1,he=null,Z=3,sr=!1,yn=!1,ct=!1,di=typeof setTimeout=="function"?setTimeout:null,pi=typeof clearTimeout=="function"?clearTimeout:null,ci=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function jl(e){for(var n=_e(Ge);n!==null;){if(n.callback===null)ir(Ge);else if(n.startTime<=e)ir(Ge),n.sortIndex=n.expirationTime,Fl(Re,n);else break;n=_e(Ge)}}function Ul(e){if(ct=!1,jl(e),!yn)if(_e(Re)!==null)yn=!0,Al(Vl);else{var n=_e(Ge);n!==null&&Hl(Ul,n.startTime-e)}}function Vl(e,n){yn=!1,ct&&(ct=!1,pi(ft),ft=-1),sr=!0;var t=Z;try{for(jl(n),he=_e(Re);he!==null&&(!(he.expirationTime>n)||e&&!hi());){var r=he.callback;if(typeof r=="function"){he.callback=null,Z=he.priorityLevel;var l=r(he.expirationTime<=n);n=L.unstable_now(),typeof l=="function"?he.callback=l:he===_e(Re)&&ir(Re),jl(n)}else ir(Re);he=_e(Re)}if(he!==null)var o=!0;else{var u=_e(Ge);u!==null&&Hl(Ul,u.startTime-n),o=!1}return o}finally{he=null,Z=t,sr=!1}}var ar=!1,ur=null,ft=-1,mi=5,vi=-1;function hi(){return!(L.unstable_now()-vie||125r?(e.sortIndex=t,Fl(Ge,e),_e(Re)===null&&e===_e(Ge)&&(ct?(pi(ft),ft=-1):ct=!0,Hl(Ul,t-r))):(e.sortIndex=l,Fl(Re,e),yn||sr||(yn=!0,Al(Vl))),e};L.unstable_shouldYield=hi;L.unstable_wrapCallback=function(e){var n=Z;return function(){var t=Z;Z=n;try{return e.apply(this,arguments)}finally{Z=t}}}});var wi=je((Cp,gi)=>{"use strict";gi.exports=yi()});var xc=je(ve=>{"use strict";var Ns=Ol(),pe=wi();function h(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),co=Object.prototype.hasOwnProperty,cf=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Si={},ki={};function ff(e){return co.call(ki,e)?!0:co.call(Si,e)?!1:cf.test(e)?ki[e]=!0:(Si[e]=!0,!1)}function df(e,n,t,r){if(t!==null&&t.type===0)return!1;switch(typeof n){case"function":case"symbol":return!0;case"boolean":return r?!1:t!==null?!t.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function pf(e,n,t,r){if(n===null||typeof n>"u"||df(e,n,t,r))return!0;if(r)return!1;if(t!==null)switch(t.type){case 3:return!n;case 4:return n===!1;case 5:return isNaN(n);case 6:return isNaN(n)||1>n}return!1}function le(e,n,t,r,l,o,u){this.acceptsBooleans=n===2||n===3||n===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=t,this.propertyName=e,this.type=n,this.sanitizeURL=o,this.removeEmptyString=u}var G={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){G[e]=new le(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var n=e[0];G[n]=new le(n,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){G[e]=new le(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){G[e]=new le(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){G[e]=new le(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){G[e]=new le(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){G[e]=new le(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){G[e]=new le(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){G[e]=new le(e,5,!1,e.toLowerCase(),null,!1,!1)});var ru=/[\-:]([a-z])/g;function lu(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var n=e.replace(ru,lu);G[n]=new le(n,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var n=e.replace(ru,lu);G[n]=new le(n,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var n=e.replace(ru,lu);G[n]=new le(n,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){G[e]=new le(e,1,!1,e.toLowerCase(),null,!1,!1)});G.xlinkHref=new le("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){G[e]=new le(e,1,!1,e.toLowerCase(),null,!0,!0)});function ou(e,n,t,r){var l=G.hasOwnProperty(n)?G[n]:null;(l!==null?l.type!==0:r||!(2i||l[u]!==o[i]){var s=` +`+l[u].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=u&&0<=i);break}}}finally{Wl=!1,Error.prepareStackTrace=t}return(e=e?e.displayName||e.name:"")?St(e):""}function mf(e){switch(e.tag){case 5:return St(e.type);case 16:return St("Lazy");case 13:return St("Suspense");case 19:return St("SuspenseList");case 0:case 2:case 15:return e=$l(e.type,!1),e;case 11:return e=$l(e.type.render,!1),e;case 1:return e=$l(e.type,!0),e;default:return""}}function vo(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Fn:return"Fragment";case In:return"Portal";case fo:return"Profiler";case uu:return"StrictMode";case po:return"Suspense";case mo:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Ts:return(e.displayName||"Context")+".Consumer";case zs:return(e._context.displayName||"Context")+".Provider";case iu:var n=e.render;return e=e.displayName,e||(e=n.displayName||n.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case su:return n=e.displayName||null,n!==null?n:vo(e.type)||"Memo";case Je:n=e._payload,e=e._init;try{return vo(e(n))}catch{}}return null}function vf(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=n.render,e=e.displayName||e.name||"",n.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return vo(n);case 8:return n===uu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof n=="function")return n.displayName||n.name||null;if(typeof n=="string")return n}return null}function dn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Rs(e){var n=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(n==="checkbox"||n==="radio")}function hf(e){var n=Rs(e)?"checked":"value",t=Object.getOwnPropertyDescriptor(e.constructor.prototype,n),r=""+e[n];if(!e.hasOwnProperty(n)&&typeof t<"u"&&typeof t.get=="function"&&typeof t.set=="function"){var l=t.get,o=t.set;return Object.defineProperty(e,n,{configurable:!0,get:function(){return l.call(this)},set:function(u){r=""+u,o.call(this,u)}}),Object.defineProperty(e,n,{enumerable:t.enumerable}),{getValue:function(){return r},setValue:function(u){r=""+u},stopTracking:function(){e._valueTracker=null,delete e[n]}}}}function fr(e){e._valueTracker||(e._valueTracker=hf(e))}function Os(e){if(!e)return!1;var n=e._valueTracker;if(!n)return!0;var t=n.getValue(),r="";return e&&(r=Rs(e)?e.checked?"true":"false":e.value),e=r,e!==t?(n.setValue(e),!0):!1}function Vr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ho(e,n){var t=n.checked;return j({},n,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:t??e._wrapperState.initialChecked})}function _i(e,n){var t=n.defaultValue==null?"":n.defaultValue,r=n.checked!=null?n.checked:n.defaultChecked;t=dn(n.value!=null?n.value:t),e._wrapperState={initialChecked:r,initialValue:t,controlled:n.type==="checkbox"||n.type==="radio"?n.checked!=null:n.value!=null}}function Ds(e,n){n=n.checked,n!=null&&ou(e,"checked",n,!1)}function yo(e,n){Ds(e,n);var t=dn(n.value),r=n.type;if(t!=null)r==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+t):e.value!==""+t&&(e.value=""+t);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}n.hasOwnProperty("value")?go(e,n.type,t):n.hasOwnProperty("defaultValue")&&go(e,n.type,dn(n.defaultValue)),n.checked==null&&n.defaultChecked!=null&&(e.defaultChecked=!!n.defaultChecked)}function Ci(e,n,t){if(n.hasOwnProperty("value")||n.hasOwnProperty("defaultValue")){var r=n.type;if(!(r!=="submit"&&r!=="reset"||n.value!==void 0&&n.value!==null))return;n=""+e._wrapperState.initialValue,t||n===e.value||(e.value=n),e.defaultValue=n}t=e.name,t!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,t!==""&&(e.name=t)}function go(e,n,t){(n!=="number"||Vr(e.ownerDocument)!==e)&&(t==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+t&&(e.defaultValue=""+t))}var kt=Array.isArray;function Yn(e,n,t,r){if(e=e.options,n){n={};for(var l=0;l"+n.valueOf().toString()+"",n=dr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;n.firstChild;)e.appendChild(n.firstChild)}});function Mt(e,n){if(n){var t=e.firstChild;if(t&&t===e.lastChild&&t.nodeType===3){t.nodeValue=n;return}}e.textContent=n}var Ct={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},yf=["Webkit","ms","Moz","O"];Object.keys(Ct).forEach(function(e){yf.forEach(function(n){n=n+e.charAt(0).toUpperCase()+e.substring(1),Ct[n]=Ct[e]})});function js(e,n,t){return n==null||typeof n=="boolean"||n===""?"":t||typeof n!="number"||n===0||Ct.hasOwnProperty(e)&&Ct[e]?(""+n).trim():n+"px"}function Us(e,n){e=e.style;for(var t in n)if(n.hasOwnProperty(t)){var r=t.indexOf("--")===0,l=js(t,n[t],r);t==="float"&&(t="cssFloat"),r?e.setProperty(t,l):e[t]=l}}var gf=j({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ko(e,n){if(n){if(gf[e]&&(n.children!=null||n.dangerouslySetInnerHTML!=null))throw Error(h(137,e));if(n.dangerouslySetInnerHTML!=null){if(n.children!=null)throw Error(h(60));if(typeof n.dangerouslySetInnerHTML!="object"||!("__html"in n.dangerouslySetInnerHTML))throw Error(h(61))}if(n.style!=null&&typeof n.style!="object")throw Error(h(62))}}function Eo(e,n){if(e.indexOf("-")===-1)return typeof n.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var _o=null;function au(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Co=null,Xn=null,Gn=null;function Pi(e){if(e=qt(e)){if(typeof Co!="function")throw Error(h(280));var n=e.stateNode;n&&(n=pl(n),Co(e.stateNode,e.type,n))}}function Vs(e){Xn?Gn?Gn.push(e):Gn=[e]:Xn=e}function As(){if(Xn){var e=Xn,n=Gn;if(Gn=Xn=null,Pi(e),n)for(e=0;e>>=0,e===0?32:31-(Tf(e)/Lf|0)|0}var pr=64,mr=4194304;function Et(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Wr(e,n){var t=e.pendingLanes;if(t===0)return 0;var r=0,l=e.suspendedLanes,o=e.pingedLanes,u=t&268435455;if(u!==0){var i=u&~l;i!==0?r=Et(i):(o&=u,o!==0&&(r=Et(o)))}else u=t&~l,u!==0?r=Et(u):o!==0&&(r=Et(o));if(r===0)return 0;if(n!==0&&n!==r&&!(n&l)&&(l=r&-r,o=n&-n,l>=o||l===16&&(o&4194240)!==0))return n;if(r&4&&(r|=t&16),n=e.entangledLanes,n!==0)for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function Zt(e,n,t){e.pendingLanes|=n,n!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,n=31-ze(n),e[n]=t}function Mf(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Nt),Fi=" ",ji=!1;function ua(e,n){switch(e){case"keyup":return sd.indexOf(n.keyCode)!==-1;case"keydown":return n.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ia(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var jn=!1;function cd(e,n){switch(e){case"compositionend":return ia(n);case"keypress":return n.which!==32?null:(ji=!0,Fi);case"textInput":return e=n.data,e===Fi&&ji?null:e;default:return null}}function fd(e,n){if(jn)return e==="compositionend"||!yu&&ua(e,n)?(e=la(),Lr=mu=nn=null,jn=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(n.ctrlKey||n.altKey||n.metaKey)||n.ctrlKey&&n.altKey){if(n.char&&1=n)return{node:t,offset:n-e};e=r}e:{for(;t;){if(t.nextSibling){t=t.nextSibling;break e}t=t.parentNode}t=void 0}t=Ai(t)}}function fa(e,n){return e&&n?e===n?!0:e&&e.nodeType===3?!1:n&&n.nodeType===3?fa(e,n.parentNode):"contains"in e?e.contains(n):e.compareDocumentPosition?!!(e.compareDocumentPosition(n)&16):!1:!1}function da(){for(var e=window,n=Vr();n instanceof e.HTMLIFrameElement;){try{var t=typeof n.contentWindow.location.href=="string"}catch{t=!1}if(t)e=n.contentWindow;else break;n=Vr(e.document)}return n}function gu(e){var n=e&&e.nodeName&&e.nodeName.toLowerCase();return n&&(n==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||n==="textarea"||e.contentEditable==="true")}function Sd(e){var n=da(),t=e.focusedElem,r=e.selectionRange;if(n!==t&&t&&t.ownerDocument&&fa(t.ownerDocument.documentElement,t)){if(r!==null&&gu(t)){if(n=r.start,e=r.end,e===void 0&&(e=n),"selectionStart"in t)t.selectionStart=n,t.selectionEnd=Math.min(e,t.value.length);else if(e=(n=t.ownerDocument||document)&&n.defaultView||window,e.getSelection){e=e.getSelection();var l=t.textContent.length,o=Math.min(r.start,l);r=r.end===void 0?o:Math.min(r.end,l),!e.extend&&o>r&&(l=r,r=o,o=l),l=Hi(t,o);var u=Hi(t,r);l&&u&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==u.node||e.focusOffset!==u.offset)&&(n=n.createRange(),n.setStart(l.node,l.offset),e.removeAllRanges(),o>r?(e.addRange(n),e.extend(u.node,u.offset)):(n.setEnd(u.node,u.offset),e.addRange(n)))}}for(n=[],e=t;e=e.parentNode;)e.nodeType===1&&n.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof t.focus=="function"&&t.focus(),t=0;t=document.documentMode,Un=null,Lo=null,zt=null,Ro=!1;function Bi(e,n,t){var r=t.window===t?t.document:t.nodeType===9?t:t.ownerDocument;Ro||Un==null||Un!==Vr(r)||(r=Un,"selectionStart"in r&&gu(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),zt&&At(zt,r)||(zt=r,r=Kr(Lo,"onSelect"),0Hn||(e.current=jo[Hn],jo[Hn]=null,Hn--)}function R(e,n){Hn++,jo[Hn]=e.current,e.current=n}var pn={},ee=vn(pn),ie=vn(!1),xn=pn;function et(e,n){var t=e.type.contextTypes;if(!t)return pn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l={},o;for(o in t)l[o]=n[o];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=l),l}function se(e){return e=e.childContextTypes,e!=null}function Xr(){D(ie),D(ee)}function Ji(e,n,t){if(ee.current!==pn)throw Error(h(168));R(ee,n),R(ie,t)}function ka(e,n,t){var r=e.stateNode;if(n=n.childContextTypes,typeof r.getChildContext!="function")return t;r=r.getChildContext();for(var l in r)if(!(l in n))throw Error(h(108,vf(e)||"Unknown",l));return j({},t,r)}function Gr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||pn,xn=ee.current,R(ee,e),R(ie,ie.current),!0}function qi(e,n,t){var r=e.stateNode;if(!r)throw Error(h(169));t?(e=ka(e,n,xn),r.__reactInternalMemoizedMergedChildContext=e,D(ie),D(ee),R(ee,e)):D(ie),R(ie,t)}var Ve=null,ml=!1,no=!1;function Ea(e){Ve===null?Ve=[e]:Ve.push(e)}function Ld(e){ml=!0,Ea(e)}function hn(){if(!no&&Ve!==null){no=!0;var e=0,n=T;try{var t=Ve;for(T=1;e>=u,l-=u,Ae=1<<32-ze(n)+l|t<x?($=C,C=null):$=C.sibling;var z=p(c,C,d[x],y);if(z===null){C===null&&(C=$);break}e&&C&&z.alternate===null&&n(c,C),a=o(z,a,x),_===null?E=z:_.sibling=z,_=z,C=$}if(x===d.length)return t(c,C),M&&gn(c,x),E;if(C===null){for(;xx?($=C,C=null):$=C.sibling;var Xe=p(c,C,z.value,y);if(Xe===null){C===null&&(C=$);break}e&&C&&Xe.alternate===null&&n(c,C),a=o(Xe,a,x),_===null?E=Xe:_.sibling=Xe,_=Xe,C=$}if(z.done)return t(c,C),M&&gn(c,x),E;if(C===null){for(;!z.done;x++,z=d.next())z=v(c,z.value,y),z!==null&&(a=o(z,a,x),_===null?E=z:_.sibling=z,_=z);return M&&gn(c,x),E}for(C=r(c,C);!z.done;x++,z=d.next())z=g(C,c,x,z.value,y),z!==null&&(e&&z.alternate!==null&&C.delete(z.key===null?x:z.key),a=o(z,a,x),_===null?E=z:_.sibling=z,_=z);return e&&C.forEach(function(Vc){return n(c,Vc)}),M&&gn(c,x),E}function V(c,a,d,y){if(typeof d=="object"&&d!==null&&d.type===Fn&&d.key===null&&(d=d.props.children),typeof d=="object"&&d!==null){switch(d.$$typeof){case cr:e:{for(var E=d.key,_=a;_!==null;){if(_.key===E){if(E=d.type,E===Fn){if(_.tag===7){t(c,_.sibling),a=l(_,d.props.children),a.return=c,c=a;break e}}else if(_.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===Je&&os(E)===_.type){t(c,_.sibling),a=l(_,d.props),a.ref=ht(c,_,d),a.return=c,c=a;break e}t(c,_);break}else n(c,_);_=_.sibling}d.type===Fn?(a=Cn(d.props.children,c.mode,y,d.key),a.return=c,c=a):(y=Ur(d.type,d.key,d.props,null,c.mode,y),y.ref=ht(c,a,d),y.return=c,c=y)}return u(c);case In:e:{for(_=d.key;a!==null;){if(a.key===_)if(a.tag===4&&a.stateNode.containerInfo===d.containerInfo&&a.stateNode.implementation===d.implementation){t(c,a.sibling),a=l(a,d.children||[]),a.return=c,c=a;break e}else{t(c,a);break}else n(c,a);a=a.sibling}a=ao(d,c.mode,y),a.return=c,c=a}return u(c);case Je:return _=d._init,V(c,a,_(d._payload),y)}if(kt(d))return S(c,a,d,y);if(dt(d))return k(c,a,d,y);xr(c,d)}return typeof d=="string"&&d!==""||typeof d=="number"?(d=""+d,a!==null&&a.tag===6?(t(c,a.sibling),a=l(a,d),a.return=c,c=a):(t(c,a),a=so(d,c.mode,y),a.return=c,c=a),u(c)):t(c,a)}return V}var tt=La(!0),Ra=La(!1),bt={},Fe=vn(bt),$t=vn(bt),Qt=vn(bt);function En(e){if(e===bt)throw Error(h(174));return e}function Pu(e,n){switch(R(Qt,n),R($t,e),R(Fe,bt),e=n.nodeType,e){case 9:case 11:n=(n=n.documentElement)?n.namespaceURI:So(null,"");break;default:e=e===8?n.parentNode:n,n=e.namespaceURI||null,e=e.tagName,n=So(n,e)}D(Fe),R(Fe,n)}function rt(){D(Fe),D($t),D(Qt)}function Oa(e){En(Qt.current);var n=En(Fe.current),t=So(n,e.type);n!==t&&(R($t,e),R(Fe,t))}function zu(e){$t.current===e&&(D(Fe),D($t))}var I=vn(0);function nl(e){for(var n=e;n!==null;){if(n.tag===13){var t=n.memoizedState;if(t!==null&&(t=t.dehydrated,t===null||t.data==="$?"||t.data==="$!"))return n}else if(n.tag===19&&n.memoizedProps.revealOrder!==void 0){if(n.flags&128)return n}else if(n.child!==null){n.child.return=n,n=n.child;continue}if(n===e)break;for(;n.sibling===null;){if(n.return===null||n.return===e)return null;n=n.return}n.sibling.return=n.return,n=n.sibling}return null}var to=[];function Tu(){for(var e=0;et?t:4,e(!0);var r=ro.transition;ro.transition={};try{e(!1),n()}finally{T=t,ro.transition=r}}function Xa(){return Ee().memoizedState}function Md(e,n,t){var r=cn(e);if(t={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null},Ga(e))Za(n,t);else if(t=Na(e,n,t,r),t!==null){var l=re();Te(t,e,r,l),Ja(t,n,r)}}function Id(e,n,t){var r=cn(e),l={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null};if(Ga(e))Za(n,l);else{var o=e.alternate;if(e.lanes===0&&(o===null||o.lanes===0)&&(o=n.lastRenderedReducer,o!==null))try{var u=n.lastRenderedState,i=o(u,t);if(l.hasEagerState=!0,l.eagerState=i,Le(i,u)){var s=n.interleaved;s===null?(l.next=l,xu(n)):(l.next=s.next,s.next=l),n.interleaved=l;return}}catch{}finally{}t=Na(e,n,l,r),t!==null&&(l=re(),Te(t,e,r,l),Ja(t,n,r))}}function Ga(e){var n=e.alternate;return e===F||n!==null&&n===F}function Za(e,n){Tt=tl=!0;var t=e.pending;t===null?n.next=n:(n.next=t.next,t.next=n),e.pending=n}function Ja(e,n,t){if(t&4194240){var r=n.lanes;r&=e.pendingLanes,t|=r,n.lanes=t,fu(e,t)}}var rl={readContext:ke,useCallback:J,useContext:J,useEffect:J,useImperativeHandle:J,useInsertionEffect:J,useLayoutEffect:J,useMemo:J,useReducer:J,useRef:J,useState:J,useDebugValue:J,useDeferredValue:J,useTransition:J,useMutableSource:J,useSyncExternalStore:J,useId:J,unstable_isNewReconciler:!1},Fd={readContext:ke,useCallback:function(e,n){return De().memoizedState=[e,n===void 0?null:n],e},useContext:ke,useEffect:is,useImperativeHandle:function(e,n,t){return t=t!=null?t.concat([e]):null,Mr(4194308,4,Wa.bind(null,n,e),t)},useLayoutEffect:function(e,n){return Mr(4194308,4,e,n)},useInsertionEffect:function(e,n){return Mr(4,2,e,n)},useMemo:function(e,n){var t=De();return n=n===void 0?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=De();return n=t!==void 0?t(n):n,r.memoizedState=r.baseState=n,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},r.queue=e,e=e.dispatch=Md.bind(null,F,e),[r.memoizedState,e]},useRef:function(e){var n=De();return e={current:e},n.memoizedState=e},useState:us,useDebugValue:Mu,useDeferredValue:function(e){return De().memoizedState=e},useTransition:function(){var e=us(!1),n=e[0];return e=Dd.bind(null,e[1]),De().memoizedState=e,[n,e]},useMutableSource:function(){},useSyncExternalStore:function(e,n,t){var r=F,l=De();if(M){if(t===void 0)throw Error(h(407));t=t()}else{if(t=n(),K===null)throw Error(h(349));Pn&30||Ia(r,n,t)}l.memoizedState=t;var o={value:t,getSnapshot:n};return l.queue=o,is(ja.bind(null,r,o,e),[e]),r.flags|=2048,Xt(9,Fa.bind(null,r,o,t,n),void 0,null),t},useId:function(){var e=De(),n=K.identifierPrefix;if(M){var t=He,r=Ae;t=(r&~(1<<32-ze(r)-1)).toString(32)+t,n=":"+n+"R"+t,t=Kt++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=u.createElement(t,{is:r.is}):(e=u.createElement(t),t==="select"&&(u=e,r.multiple?u.multiple=!0:r.size&&(u.size=r.size))):e=u.createElementNS(e,t),e[Me]=n,e[Wt]=r,uc(e,n,!1,!1),n.stateNode=e;e:{switch(u=Eo(t,r),t){case"dialog":O("cancel",e),O("close",e),l=r;break;case"iframe":case"object":case"embed":O("load",e),l=r;break;case"video":case"audio":for(l=0;l<_t.length;l++)O(_t[l],e);l=r;break;case"source":O("error",e),l=r;break;case"img":case"image":case"link":O("error",e),O("load",e),l=r;break;case"details":O("toggle",e),l=r;break;case"input":_i(e,r),l=ho(e,r),O("invalid",e);break;case"option":l=r;break;case"select":e._wrapperState={wasMultiple:!!r.multiple},l=j({},r,{value:void 0}),O("invalid",e);break;case"textarea":xi(e,r),l=wo(e,r),O("invalid",e);break;default:l=r}ko(t,l),i=l;for(o in i)if(i.hasOwnProperty(o)){var s=i[o];o==="style"?Us(e,s):o==="dangerouslySetInnerHTML"?(s=s?s.__html:void 0,s!=null&&Fs(e,s)):o==="children"?typeof s=="string"?(t!=="textarea"||s!=="")&&Mt(e,s):typeof s=="number"&&Mt(e,""+s):o!=="suppressContentEditableWarning"&&o!=="suppressHydrationWarning"&&o!=="autoFocus"&&(Dt.hasOwnProperty(o)?s!=null&&o==="onScroll"&&O("scroll",e):s!=null&&ou(e,o,s,u))}switch(t){case"input":fr(e),Ci(e,r,!1);break;case"textarea":fr(e),Ni(e);break;case"option":r.value!=null&&e.setAttribute("value",""+dn(r.value));break;case"select":e.multiple=!!r.multiple,o=r.value,o!=null?Yn(e,!!r.multiple,o,!1):r.defaultValue!=null&&Yn(e,!!r.multiple,r.defaultValue,!0);break;default:typeof l.onClick=="function"&&(e.onclick=Yr)}switch(t){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}}r&&(n.flags|=4)}n.ref!==null&&(n.flags|=512,n.flags|=2097152)}return q(n),null;case 6:if(e&&n.stateNode!=null)sc(e,n,e.memoizedProps,r);else{if(typeof r!="string"&&n.stateNode===null)throw Error(h(166));if(t=En(Qt.current),En(Fe.current),Cr(n)){if(r=n.stateNode,t=n.memoizedProps,r[Me]=n,(o=r.nodeValue!==t)&&(e=de,e!==null))switch(e.tag){case 3:_r(r.nodeValue,t,(e.mode&1)!==0);break;case 5:e.memoizedProps.suppressHydrationWarning!==!0&&_r(r.nodeValue,t,(e.mode&1)!==0)}o&&(n.flags|=4)}else r=(t.nodeType===9?t:t.ownerDocument).createTextNode(r),r[Me]=n,n.stateNode=r}return q(n),null;case 13:if(D(I),r=n.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(M&&fe!==null&&n.mode&1&&!(n.flags&128))xa(),nt(),n.flags|=98560,o=!1;else if(o=Cr(n),r!==null&&r.dehydrated!==null){if(e===null){if(!o)throw Error(h(318));if(o=n.memoizedState,o=o!==null?o.dehydrated:null,!o)throw Error(h(317));o[Me]=n}else nt(),!(n.flags&128)&&(n.memoizedState=null),n.flags|=4;q(n),o=!1}else Pe!==null&&(tu(Pe),Pe=null),o=!0;if(!o)return n.flags&65536?n:null}return n.flags&128?(n.lanes=t,n):(r=r!==null,r!==(e!==null&&e.memoizedState!==null)&&r&&(n.child.flags|=8192,n.mode&1&&(e===null||I.current&1?W===0&&(W=3):Hu())),n.updateQueue!==null&&(n.flags|=4),q(n),null);case 4:return rt(),Xo(e,n),e===null&&Ht(n.stateNode.containerInfo),q(n),null;case 10:return Cu(n.type._context),q(n),null;case 17:return se(n.type)&&Xr(),q(n),null;case 19:if(D(I),o=n.memoizedState,o===null)return q(n),null;if(r=(n.flags&128)!==0,u=o.rendering,u===null)if(r)yt(o,!1);else{if(W!==0||e!==null&&e.flags&128)for(e=n.child;e!==null;){if(u=nl(e),u!==null){for(n.flags|=128,yt(o,!1),r=u.updateQueue,r!==null&&(n.updateQueue=r,n.flags|=4),n.subtreeFlags=0,r=t,t=n.child;t!==null;)o=t,e=r,o.flags&=14680066,u=o.alternate,u===null?(o.childLanes=0,o.lanes=e,o.child=null,o.subtreeFlags=0,o.memoizedProps=null,o.memoizedState=null,o.updateQueue=null,o.dependencies=null,o.stateNode=null):(o.childLanes=u.childLanes,o.lanes=u.lanes,o.child=u.child,o.subtreeFlags=0,o.deletions=null,o.memoizedProps=u.memoizedProps,o.memoizedState=u.memoizedState,o.updateQueue=u.updateQueue,o.type=u.type,e=u.dependencies,o.dependencies=e===null?null:{lanes:e.lanes,firstContext:e.firstContext}),t=t.sibling;return R(I,I.current&1|2),n.child}e=e.sibling}o.tail!==null&&A()>ot&&(n.flags|=128,r=!0,yt(o,!1),n.lanes=4194304)}else{if(!r)if(e=nl(u),e!==null){if(n.flags|=128,r=!0,t=e.updateQueue,t!==null&&(n.updateQueue=t,n.flags|=4),yt(o,!0),o.tail===null&&o.tailMode==="hidden"&&!u.alternate&&!M)return q(n),null}else 2*A()-o.renderingStartTime>ot&&t!==1073741824&&(n.flags|=128,r=!0,yt(o,!1),n.lanes=4194304);o.isBackwards?(u.sibling=n.child,n.child=u):(t=o.last,t!==null?t.sibling=u:n.child=u,o.last=u)}return o.tail!==null?(n=o.tail,o.rendering=n,o.tail=n.sibling,o.renderingStartTime=A(),n.sibling=null,t=I.current,R(I,r?t&1|2:t&1),n):(q(n),null);case 22:case 23:return Au(),r=n.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(n.flags|=8192),r&&n.mode&1?ce&1073741824&&(q(n),n.subtreeFlags&6&&(n.flags|=8192)):q(n),null;case 24:return null;case 25:return null}throw Error(h(156,n.tag))}function $d(e,n){switch(Su(n),n.tag){case 1:return se(n.type)&&Xr(),e=n.flags,e&65536?(n.flags=e&-65537|128,n):null;case 3:return rt(),D(ie),D(ee),Tu(),e=n.flags,e&65536&&!(e&128)?(n.flags=e&-65537|128,n):null;case 5:return zu(n),null;case 13:if(D(I),e=n.memoizedState,e!==null&&e.dehydrated!==null){if(n.alternate===null)throw Error(h(340));nt()}return e=n.flags,e&65536?(n.flags=e&-65537|128,n):null;case 19:return D(I),null;case 4:return rt(),null;case 10:return Cu(n.type._context),null;case 22:case 23:return Au(),null;case 24:return null;default:return null}}var Pr=!1,b=!1,Qd=typeof WeakSet=="function"?WeakSet:Set,w=null;function Qn(e,n){var t=e.ref;if(t!==null)if(typeof t=="function")try{t(null)}catch(r){U(e,n,r)}else t.current=null}function Go(e,n,t){try{t()}catch(r){U(e,n,r)}}var hs=!1;function Kd(e,n){if(Oo=$r,e=da(),gu(e)){if("selectionStart"in e)var t={start:e.selectionStart,end:e.selectionEnd};else e:{t=(t=e.ownerDocument)&&t.defaultView||window;var r=t.getSelection&&t.getSelection();if(r&&r.rangeCount!==0){t=r.anchorNode;var l=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{t.nodeType,o.nodeType}catch{t=null;break e}var u=0,i=-1,s=-1,f=0,m=0,v=e,p=null;n:for(;;){for(var g;v!==t||l!==0&&v.nodeType!==3||(i=u+l),v!==o||r!==0&&v.nodeType!==3||(s=u+r),v.nodeType===3&&(u+=v.nodeValue.length),(g=v.firstChild)!==null;)p=v,v=g;for(;;){if(v===e)break n;if(p===t&&++f===l&&(i=u),p===o&&++m===r&&(s=u),(g=v.nextSibling)!==null)break;v=p,p=v.parentNode}v=g}t=i===-1||s===-1?null:{start:i,end:s}}else t=null}t=t||{start:0,end:0}}else t=null;for(Do={focusedElem:e,selectionRange:t},$r=!1,w=n;w!==null;)if(n=w,e=n.child,(n.subtreeFlags&1028)!==0&&e!==null)e.return=n,w=e;else for(;w!==null;){n=w;try{var S=n.alternate;if(n.flags&1024)switch(n.tag){case 0:case 11:case 15:break;case 1:if(S!==null){var k=S.memoizedProps,V=S.memoizedState,c=n.stateNode,a=c.getSnapshotBeforeUpdate(n.elementType===n.type?k:xe(n.type,k),V);c.__reactInternalSnapshotBeforeUpdate=a}break;case 3:var d=n.stateNode.containerInfo;d.nodeType===1?d.textContent="":d.nodeType===9&&d.documentElement&&d.removeChild(d.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(h(163))}}catch(y){U(n,n.return,y)}if(e=n.sibling,e!==null){e.return=n.return,w=e;break}w=n.return}return S=hs,hs=!1,S}function Lt(e,n,t){var r=n.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var o=l.destroy;l.destroy=void 0,o!==void 0&&Go(n,t,o)}l=l.next}while(l!==r)}}function yl(e,n){if(n=n.updateQueue,n=n!==null?n.lastEffect:null,n!==null){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function Zo(e){var n=e.ref;if(n!==null){var t=e.stateNode;switch(e.tag){case 5:e=t;break;default:e=t}typeof n=="function"?n(e):n.current=e}}function ac(e){var n=e.alternate;n!==null&&(e.alternate=null,ac(n)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(n=e.stateNode,n!==null&&(delete n[Me],delete n[Wt],delete n[Fo],delete n[zd],delete n[Td])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function cc(e){return e.tag===5||e.tag===3||e.tag===4}function ys(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||cc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Jo(e,n,t){var r=e.tag;if(r===5||r===6)e=e.stateNode,n?t.nodeType===8?t.parentNode.insertBefore(e,n):t.insertBefore(e,n):(t.nodeType===8?(n=t.parentNode,n.insertBefore(e,t)):(n=t,n.appendChild(e)),t=t._reactRootContainer,t!=null||n.onclick!==null||(n.onclick=Yr));else if(r!==4&&(e=e.child,e!==null))for(Jo(e,n,t),e=e.sibling;e!==null;)Jo(e,n,t),e=e.sibling}function qo(e,n,t){var r=e.tag;if(r===5||r===6)e=e.stateNode,n?t.insertBefore(e,n):t.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(qo(e,n,t),e=e.sibling;e!==null;)qo(e,n,t),e=e.sibling}var Y=null,Ne=!1;function Ze(e,n,t){for(t=t.child;t!==null;)fc(e,n,t),t=t.sibling}function fc(e,n,t){if(Ie&&typeof Ie.onCommitFiberUnmount=="function")try{Ie.onCommitFiberUnmount(al,t)}catch{}switch(t.tag){case 5:b||Qn(t,n);case 6:var r=Y,l=Ne;Y=null,Ze(e,n,t),Y=r,Ne=l,Y!==null&&(Ne?(e=Y,t=t.stateNode,e.nodeType===8?e.parentNode.removeChild(t):e.removeChild(t)):Y.removeChild(t.stateNode));break;case 18:Y!==null&&(Ne?(e=Y,t=t.stateNode,e.nodeType===8?eo(e.parentNode,t):e.nodeType===1&&eo(e,t),Ut(e)):eo(Y,t.stateNode));break;case 4:r=Y,l=Ne,Y=t.stateNode.containerInfo,Ne=!0,Ze(e,n,t),Y=r,Ne=l;break;case 0:case 11:case 14:case 15:if(!b&&(r=t.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var o=l,u=o.destroy;o=o.tag,u!==void 0&&(o&2||o&4)&&Go(t,n,u),l=l.next}while(l!==r)}Ze(e,n,t);break;case 1:if(!b&&(Qn(t,n),r=t.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=t.memoizedProps,r.state=t.memoizedState,r.componentWillUnmount()}catch(i){U(t,n,i)}Ze(e,n,t);break;case 21:Ze(e,n,t);break;case 22:t.mode&1?(b=(r=b)||t.memoizedState!==null,Ze(e,n,t),b=r):Ze(e,n,t);break;default:Ze(e,n,t)}}function gs(e){var n=e.updateQueue;if(n!==null){e.updateQueue=null;var t=e.stateNode;t===null&&(t=e.stateNode=new Qd),n.forEach(function(r){var l=np.bind(null,e,r);t.has(r)||(t.add(r),r.then(l,l))})}}function Ce(e,n){var t=n.deletions;if(t!==null)for(var r=0;rl&&(l=u),r&=~o}if(r=l,r=A()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Xd(r/1960))-r,10e?16:e,tn===null)var r=!1;else{if(e=tn,tn=null,ul=0,P&6)throw Error(h(331));var l=P;for(P|=4,w=e.current;w!==null;){var o=w,u=o.child;if(w.flags&16){var i=o.deletions;if(i!==null){for(var s=0;sA()-Uu?_n(e,0):ju|=t),ae(e,n)}function wc(e,n){n===0&&(e.mode&1?(n=mr,mr<<=1,!(mr&130023424)&&(mr=4194304)):n=1);var t=re();e=Qe(e,n),e!==null&&(Zt(e,n,t),ae(e,t))}function ep(e){var n=e.memoizedState,t=0;n!==null&&(t=n.retryLane),wc(e,t)}function np(e,n){var t=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(t=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(h(314))}r!==null&&r.delete(n),wc(e,t)}var Sc;Sc=function(e,n,t){if(e!==null)if(e.memoizedProps!==n.pendingProps||ie.current)ue=!0;else{if(!(e.lanes&t)&&!(n.flags&128))return ue=!1,Bd(e,n,t);ue=!!(e.flags&131072)}else ue=!1,M&&n.flags&1048576&&_a(n,Jr,n.index);switch(n.lanes=0,n.tag){case 2:var r=n.type;Ir(e,n),e=n.pendingProps;var l=et(n,ee.current);Jn(n,t),l=Ru(null,n,r,e,l,t);var o=Ou();return n.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(n.tag=1,n.memoizedState=null,n.updateQueue=null,se(r)?(o=!0,Gr(n)):o=!1,n.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Nu(n),l.updater=vl,n.stateNode=l,l._reactInternals=n,Bo(n,r,e,t),n=Qo(null,n,r,!0,o,t)):(n.tag=0,M&&o&&wu(n),te(null,n,l,t),n=n.child),n;case 16:r=n.elementType;e:{switch(Ir(e,n),e=n.pendingProps,l=r._init,r=l(r._payload),n.type=r,l=n.tag=rp(r),e=xe(r,e),l){case 0:n=$o(null,n,r,e,t);break e;case 1:n=ps(null,n,r,e,t);break e;case 11:n=fs(null,n,r,e,t);break e;case 14:n=ds(null,n,r,xe(r.type,e),t);break e}throw Error(h(306,r,""))}return n;case 0:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:xe(r,l),$o(e,n,r,l,t);case 1:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:xe(r,l),ps(e,n,r,l,t);case 3:e:{if(rc(n),e===null)throw Error(h(387));r=n.pendingProps,o=n.memoizedState,l=o.element,Pa(e,n),el(n,r,null,t);var u=n.memoizedState;if(r=u.element,o.isDehydrated)if(o={element:r,isDehydrated:!1,cache:u.cache,pendingSuspenseBoundaries:u.pendingSuspenseBoundaries,transitions:u.transitions},n.updateQueue.baseState=o,n.memoizedState=o,n.flags&256){l=lt(Error(h(423)),n),n=ms(e,n,r,t,l);break e}else if(r!==l){l=lt(Error(h(424)),n),n=ms(e,n,r,t,l);break e}else for(fe=un(n.stateNode.containerInfo.firstChild),de=n,M=!0,Pe=null,t=Ra(n,null,r,t),n.child=t;t;)t.flags=t.flags&-3|4096,t=t.sibling;else{if(nt(),r===l){n=Ke(e,n,t);break e}te(e,n,r,t)}n=n.child}return n;case 5:return Oa(n),e===null&&Vo(n),r=n.type,l=n.pendingProps,o=e!==null?e.memoizedProps:null,u=l.children,Mo(r,l)?u=null:o!==null&&Mo(r,o)&&(n.flags|=32),tc(e,n),te(e,n,u,t),n.child;case 6:return e===null&&Vo(n),null;case 13:return lc(e,n,t);case 4:return Pu(n,n.stateNode.containerInfo),r=n.pendingProps,e===null?n.child=tt(n,null,r,t):te(e,n,r,t),n.child;case 11:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:xe(r,l),fs(e,n,r,l,t);case 7:return te(e,n,n.pendingProps,t),n.child;case 8:return te(e,n,n.pendingProps.children,t),n.child;case 12:return te(e,n,n.pendingProps.children,t),n.child;case 10:e:{if(r=n.type._context,l=n.pendingProps,o=n.memoizedProps,u=l.value,R(qr,r._currentValue),r._currentValue=u,o!==null)if(Le(o.value,u)){if(o.children===l.children&&!ie.current){n=Ke(e,n,t);break e}}else for(o=n.child,o!==null&&(o.return=n);o!==null;){var i=o.dependencies;if(i!==null){u=o.child;for(var s=i.firstContext;s!==null;){if(s.context===r){if(o.tag===1){s=Be(-1,t&-t),s.tag=2;var f=o.updateQueue;if(f!==null){f=f.shared;var m=f.pending;m===null?s.next=s:(s.next=m.next,m.next=s),f.pending=s}}o.lanes|=t,s=o.alternate,s!==null&&(s.lanes|=t),Ao(o.return,t,n),i.lanes|=t;break}s=s.next}}else if(o.tag===10)u=o.type===n.type?null:o.child;else if(o.tag===18){if(u=o.return,u===null)throw Error(h(341));u.lanes|=t,i=u.alternate,i!==null&&(i.lanes|=t),Ao(u,t,n),u=o.sibling}else u=o.child;if(u!==null)u.return=o;else for(u=o;u!==null;){if(u===n){u=null;break}if(o=u.sibling,o!==null){o.return=u.return,u=o;break}u=u.return}o=u}te(e,n,l.children,t),n=n.child}return n;case 9:return l=n.type,r=n.pendingProps.children,Jn(n,t),l=ke(l),r=r(l),n.flags|=1,te(e,n,r,t),n.child;case 14:return r=n.type,l=xe(r,n.pendingProps),l=xe(r.type,l),ds(e,n,r,l,t);case 15:return ec(e,n,n.type,n.pendingProps,t);case 17:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:xe(r,l),Ir(e,n),n.tag=1,se(r)?(e=!0,Gr(n)):e=!1,Jn(n,t),Ta(n,r,l),Bo(n,r,l,t),Qo(null,n,r,!0,e,t);case 19:return oc(e,n,t);case 22:return nc(e,n,t)}throw Error(h(156,n.tag))};function kc(e,n){return Ys(e,n)}function tp(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function we(e,n,t,r){return new tp(e,n,t,r)}function Bu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function rp(e){if(typeof e=="function")return Bu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===iu)return 11;if(e===su)return 14}return 2}function fn(e,n){var t=e.alternate;return t===null?(t=we(e.tag,n,e.key,e.mode),t.elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=e.flags&14680064,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=n===null?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function Ur(e,n,t,r,l,o){var u=2;if(r=e,typeof e=="function")Bu(e)&&(u=1);else if(typeof e=="string")u=5;else e:switch(e){case Fn:return Cn(t.children,l,o,n);case uu:u=8,l|=8;break;case fo:return e=we(12,t,n,l|2),e.elementType=fo,e.lanes=o,e;case po:return e=we(13,t,n,l),e.elementType=po,e.lanes=o,e;case mo:return e=we(19,t,n,l),e.elementType=mo,e.lanes=o,e;case Ls:return wl(t,l,o,n);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case zs:u=10;break e;case Ts:u=9;break e;case iu:u=11;break e;case su:u=14;break e;case Je:u=16,r=null;break e}throw Error(h(130,e==null?e:typeof e,""))}return n=we(u,t,n,l),n.elementType=e,n.type=r,n.lanes=o,n}function Cn(e,n,t,r){return e=we(7,e,r,n),e.lanes=t,e}function wl(e,n,t,r){return e=we(22,e,r,n),e.elementType=Ls,e.lanes=t,e.stateNode={isHidden:!1},e}function so(e,n,t){return e=we(6,e,null,n),e.lanes=t,e}function ao(e,n,t){return n=we(4,e.children!==null?e.children:[],e.key,n),n.lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function lp(e,n,t,r,l){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Kl(0),this.expirationTimes=Kl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Kl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Wu(e,n,t,r,l,o,u,i,s){return e=new lp(e,n,t,i,s),n===1?(n=1,o===!0&&(n|=8)):n=0,o=we(3,null,null,n),e.current=o,o.stateNode=e,o.memoizedState={element:r,isDehydrated:t,cache:null,transitions:null,pendingSuspenseBoundaries:null},Nu(o),e}function op(e,n,t){var r=3{"use strict";function Nc(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Nc)}catch(e){console.error(e)}}Nc(),Pc.exports=xc()});var Lc=je(Yu=>{"use strict";var Tc=zc();Yu.createRoot=Tc.createRoot,Yu.hydrateRoot=Tc.hydrateRoot;var Pp});var Oc=je(Cl=>{"use strict";var cp=Ol(),fp=Symbol.for("react.element"),dp=Symbol.for("react.fragment"),pp=Object.prototype.hasOwnProperty,mp=cp.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,vp={key:!0,ref:!0,__self:!0,__source:!0};function Rc(e,n,t){var r,l={},o=null,u=null;t!==void 0&&(o=""+t),n.key!==void 0&&(o=""+n.key),n.ref!==void 0&&(u=n.ref);for(r in n)pp.call(n,r)&&!vp.hasOwnProperty(r)&&(l[r]=n[r]);if(e&&e.defaultProps)for(r in n=e.defaultProps,n)l[r]===void 0&&(l[r]=n[r]);return{$$typeof:fp,type:e,key:o,ref:u,props:l,_owner:mp.current}}Cl.Fragment=dp;Cl.jsx=Rc;Cl.jsxs=Rc});var Xu=je((Lp,Dc)=>{"use strict";Dc.exports=Oc()});var wp={};Qc(wp,{renderHello:()=>gp});var xl=Nl(Lc());var er=Nl(Xu()),Mc=()=>(0,er.jsx)("h1",{children:"React component Header"}),Ic=()=>(0,er.jsx)("div",{children:"This is client-side content from React"}),Fc=e=>(0,er.jsxs)("div",{children:["Hello ",e," (Client-side React, rendering server-side data)"]});var jc=document.getElementById("react-header");if(!jc)throw new Error("Could not find element with id react-header");var hp=(0,xl.createRoot)(jc);hp.render(Mc());var Uc=document.getElementById("react-content");if(!Uc)throw new Error("Could not find element with id react-content");var yp=(0,xl.createRoot)(Uc);yp.render(Ic());function gp(e){let n=e.getAttribute("data-name")??"";(0,xl.createRoot)(e).render(Fc(n))}return Kc(wp);})(); +/*! Bundled license information: + +react/cjs/react.production.min.js: + (** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +scheduler/cjs/scheduler.production.min.js: + (** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react-dom/cjs/react-dom.production.min.js: + (** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react/cjs/react-jsx-runtime.production.min.js: + (** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) +*/ diff --git a/templ/examples/internationalization/components.templ b/templ/examples/internationalization/components.templ new file mode 100644 index 0000000..1552938 --- /dev/null +++ b/templ/examples/internationalization/components.templ @@ -0,0 +1,22 @@ +package main + +import "github.com/invopop/ctxi18n/i18n" + +templ page() { + + + + + { i18n.T(ctx, "hello") } + + +

{ i18n.T(ctx, "hello") }

+

{ i18n.T(ctx, "select_language") }

+ + + +} diff --git a/templ/examples/internationalization/components_templ.go b/templ/examples/internationalization/components_templ.go new file mode 100644 index 0000000..6efe6df --- /dev/null +++ b/templ/examples/internationalization/components_templ.go @@ -0,0 +1,81 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "github.com/invopop/ctxi18n/i18n" + +func page() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(i18n.T(ctx, "hello")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/internationalization/components.templ`, Line: 10, Col: 32} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(i18n.T(ctx, "hello")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/internationalization/components.templ`, Line: 13, Col: 29} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(i18n.T(ctx, "select_language")) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/internationalization/components.templ`, Line: 14, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/internationalization/go.mod b/templ/examples/internationalization/go.mod new file mode 100644 index 0000000..9ea7137 --- /dev/null +++ b/templ/examples/internationalization/go.mod @@ -0,0 +1,17 @@ +module github.com/a-h/templ/examples/internationalization + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.731 + github.com/invopop/ctxi18n v0.8.1 +) + +require ( + github.com/invopop/yaml v0.3.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/internationalization/go.sum b/templ/examples/internationalization/go.sum new file mode 100644 index 0000000..16bc8f0 --- /dev/null +++ b/templ/examples/internationalization/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/invopop/ctxi18n v0.8.1 h1:nfy5Mk6UfvLbGRBwpTi4T1g95+rmRo8bMllUmpCvVwI= +github.com/invopop/ctxi18n v0.8.1/go.mod h1:1Osw+JGYA+anHt0Z4reF36r5FtGHYjGQ+m1X7keIhPc= +github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= +github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/templ/examples/internationalization/locales/de/de.yaml b/templ/examples/internationalization/locales/de/de.yaml new file mode 100644 index 0000000..51bcc36 --- /dev/null +++ b/templ/examples/internationalization/locales/de/de.yaml @@ -0,0 +1,3 @@ +de: + hello: Hallo + select_language: Sprache auswählen diff --git a/templ/examples/internationalization/locales/en/en.yaml b/templ/examples/internationalization/locales/en/en.yaml new file mode 100644 index 0000000..ccd7a30 --- /dev/null +++ b/templ/examples/internationalization/locales/en/en.yaml @@ -0,0 +1,3 @@ +en: + hello: "Hello" + select_language: "Select Language" diff --git a/templ/examples/internationalization/locales/locales.go b/templ/examples/internationalization/locales/locales.go new file mode 100644 index 0000000..a020896 --- /dev/null +++ b/templ/examples/internationalization/locales/locales.go @@ -0,0 +1,9 @@ +package locales + +import "embed" + +//go:embed en +//go:embed de +//go:embed zh-cn + +var Content embed.FS diff --git a/templ/examples/internationalization/locales/zh-cn/zh-cn.yaml b/templ/examples/internationalization/locales/zh-cn/zh-cn.yaml new file mode 100644 index 0000000..8c7720a --- /dev/null +++ b/templ/examples/internationalization/locales/zh-cn/zh-cn.yaml @@ -0,0 +1,3 @@ +zh-cn: + hello: "你好" + select_language: "选择语言" diff --git a/templ/examples/internationalization/main.go b/templ/examples/internationalization/main.go new file mode 100644 index 0000000..f3735c2 --- /dev/null +++ b/templ/examples/internationalization/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "log" + "net/http" + "strings" + + "github.com/a-h/templ" + "github.com/a-h/templ/examples/internationalization/locales" + "github.com/invopop/ctxi18n" +) + +func newLanguageMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lang := "en" // Default language + pathSegments := strings.Split(r.URL.Path, "/") + if len(pathSegments) > 1 { + lang = pathSegments[1] + } + ctx, err := ctxi18n.WithLocale(r.Context(), lang) + if err != nil { + log.Printf("error setting locale: %v", err) + http.Error(w, "error setting locale", http.StatusBadRequest) + return + } + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +func main() { + if err := ctxi18n.Load(locales.Content); err != nil { + log.Fatalf("error loading locales: %v", err) + } + + mux := http.NewServeMux() + mux.Handle("/", templ.Handler(page())) + + withLanguageMiddleware := newLanguageMiddleware(mux) + + log.Println("listening on :8080") + if err := http.ListenAndServe("127.0.0.1:8080", withLanguageMiddleware); err != nil { + log.Printf("error listening: %v", err) + } +} diff --git a/templ/examples/static-generator/.gitignore b/templ/examples/static-generator/.gitignore new file mode 100644 index 0000000..a48cf0d --- /dev/null +++ b/templ/examples/static-generator/.gitignore @@ -0,0 +1 @@ +public diff --git a/templ/examples/static-generator/Dockerfile b/templ/examples/static-generator/Dockerfile new file mode 100644 index 0000000..af50ac9 --- /dev/null +++ b/templ/examples/static-generator/Dockerfile @@ -0,0 +1,3 @@ +FROM pierrezemb/gostatic +COPY ./public/ /srv/http/ +ENTRYPOINT ["/goStatic", "-port", "8080"] diff --git a/templ/examples/static-generator/blog.templ b/templ/examples/static-generator/blog.templ new file mode 100644 index 0000000..02cd21a --- /dev/null +++ b/templ/examples/static-generator/blog.templ @@ -0,0 +1,38 @@ +package main + +import ( + "github.com/gosimple/slug" + "path" +) + +templ headerComponent(title string) { + { title } +} + +templ contentComponent(title string, body templ.Component) { + +

{ title }

+
+ @body +
+ +} + +templ contentPage(title string, body templ.Component) { + + @headerComponent(title) + @contentComponent(title, body) + +} + +templ indexPage(posts []Post) { + + @headerComponent("My Blog") + +

My Blog

+ for _, post := range posts { + + } + + +} diff --git a/templ/examples/static-generator/blog_templ.go b/templ/examples/static-generator/blog_templ.go new file mode 100644 index 0000000..36bae88 --- /dev/null +++ b/templ/examples/static-generator/blog_templ.go @@ -0,0 +1,218 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "github.com/gosimple/slug" + "path" +) + +func headerComponent(title string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/static-generator/blog.templ`, Line: 9, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func contentComponent(title string, body templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/static-generator/blog.templ`, Line: 14, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = body.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func contentPage(title string, body templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerComponent(title).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = contentComponent(title, body).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func indexPage(posts []Post) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = headerComponent("My Blog").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "

My Blog

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, post := range posts { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/static-generator/fly.toml b/templ/examples/static-generator/fly.toml new file mode 100644 index 0000000..30b3b87 --- /dev/null +++ b/templ/examples/static-generator/fly.toml @@ -0,0 +1,40 @@ +# fly.toml file generated for cold-water-2865 on 2023-04-27T10:52:30+01:00 + +app = "cold-water-2865" +kill_signal = "SIGINT" +kill_timeout = 5 +primary_region = "lhr" +processes = [] + +[build] + +[env] + +[experimental] + auto_rollback = true + +[[services]] + http_checks = [] + internal_port = 8080 + processes = ["app"] + protocol = "tcp" + script_checks = [] + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + force_https = true + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 0 + timeout = "2s" diff --git a/templ/examples/static-generator/go.mod b/templ/examples/static-generator/go.mod new file mode 100644 index 0000000..4bf1f09 --- /dev/null +++ b/templ/examples/static-generator/go.mod @@ -0,0 +1,17 @@ +module github.com/a-h/templ/examples/static-generator + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/a-h/templ v0.2.233 + github.com/gosimple/slug v1.14.0 +) + +require ( + github.com/gosimple/unidecode v1.0.1 // indirect + github.com/yuin/goldmark v1.7.4 +) + +replace github.com/a-h/templ => ../../ diff --git a/templ/examples/static-generator/go.sum b/templ/examples/static-generator/go.sum new file mode 100644 index 0000000..4745191 --- /dev/null +++ b/templ/examples/static-generator/go.sum @@ -0,0 +1,8 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= +github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= +github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= +github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= +github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= diff --git a/templ/examples/static-generator/main.go b/templ/examples/static-generator/main.go new file mode 100644 index 0000000..6ca11cb --- /dev/null +++ b/templ/examples/static-generator/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "bytes" + "context" + "io" + "log" + "os" + "path" + "time" + + "github.com/a-h/templ" + "github.com/gosimple/slug" + "github.com/yuin/goldmark" +) + +type Post struct { + Date time.Time + Title string + Content string +} + +func Unsafe(html string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + _, err = io.WriteString(w, html) + return + }) +} + +func main() { + posts := []Post{ + { + Date: time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC), + Title: "Happy New Year!", + Content: `New Year is a widely celebrated occasion in the United Kingdom, marking the end of one year and the beginning of another. + +Top New Year Activities in the UK include: + +* Attending a Hogmanay celebration in Scotland +* Taking part in a local First-Foot tradition in Scotland and Northern England +* Setting personal resolutions and goals for the upcoming year +* Going for a New Year's Day walk to enjoy the fresh start +* Visiting a local pub for a celebratory toast and some cheer +`, + }, + { + Date: time.Date(2023, time.May, 1, 0, 0, 0, 0, time.UTC), + Title: "May Day", + Content: `May Day is an ancient spring festival celebrated on the first of May in the United Kingdom, embracing the arrival of warmer weather and the renewal of life. + +Top May Day Activities in the UK: + +* Dancing around the Maypole, a traditional folk activity +* Attending local village fetes and fairs +* Watching or participating in Morris dancing performances +* Enjoying the day off as a public holiday, known as Early May Bank Holiday +`, + }, + } + + // Output path. + rootPath := "public" + if err := os.Mkdir(rootPath, 0755); err != nil { + log.Fatalf("failed to create output directory: %v", err) + } + + // Create an index page. + name := path.Join(rootPath, "index.html") + f, err := os.Create(name) + if err != nil { + log.Fatalf("failed to create output file: %v", err) + } + // Write it out. + err = indexPage(posts).Render(context.Background(), f) + if err != nil { + log.Fatalf("failed to write index page: %v", err) + } + + // Create a page for each post. + for _, post := range posts { + // Create the output directory. + dir := path.Join(rootPath, post.Date.Format("2006/01/02"), slug.Make(post.Title)) + if err := os.MkdirAll(dir, 0755); err != nil && err != os.ErrExist { + log.Fatalf("failed to create dir %q: %v", dir, err) + } + + // Create the output file. + name := path.Join(dir, "index.html") + f, err := os.Create(name) + if err != nil { + log.Fatalf("failed to create output file: %v", err) + } + + // Convert the markdown to HTML, and pass it to the template. + var buf bytes.Buffer + if err := goldmark.Convert([]byte(post.Content), &buf); err != nil { + log.Fatalf("failed to convert markdown to HTML: %v", err) + } + + // Create an unsafe component containing raw HTML. + content := Unsafe(buf.String()) + + // Use templ to render the template containing the raw HTML. + err = contentPage(post.Title, content).Render(context.Background(), f) + if err != nil { + log.Fatalf("failed to write output file: %v", err) + } + } +} diff --git a/templ/examples/streaming/go.mod b/templ/examples/streaming/go.mod new file mode 100644 index 0000000..2df7ccf --- /dev/null +++ b/templ/examples/streaming/go.mod @@ -0,0 +1,9 @@ +module githbu.com/a-h/templ/examples/streaming + +go 1.23 + +toolchain go1.23.3 + +replace github.com/a-h/templ => ../../ + +require github.com/a-h/templ v0.2.707 diff --git a/templ/examples/streaming/go.sum b/templ/examples/streaming/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/examples/streaming/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/streaming/main.templ b/templ/examples/streaming/main.templ new file mode 100644 index 0000000..6dc08a8 --- /dev/null +++ b/templ/examples/streaming/main.templ @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + "net/http" + "time" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Create a channel to send data to the template. + data := make(chan string) + // Run a background process that will take 10 seconds to complete. + go func() { + // Always remember to close the channel. + defer close(data) + for i := 0; i < 10; i++ { + select { + case <-r.Context().Done(): + // Quit early if the client is no longer connected. + return + case <-time.After(time.Second): + // Send a new piece of data to the channel. + data <- fmt.Sprintf("Part %d", i+1) + } + } + }() + + // Pass the channel to the template. + component := Page(data) + + // Serve using the streaming mode of the handler. + templ.Handler(component, templ.WithStreaming()).ServeHTTP(w, r) + }) + http.ListenAndServe("127.0.0.1:8080", nil) +} + +templ Page(data chan string) { + + + + Page + + +

Page

+ for d := range data { + @templ.Flush() { +
{ d }
+ } + } + + +} diff --git a/templ/examples/streaming/main_templ.go b/templ/examples/streaming/main_templ.go new file mode 100644 index 0000000..b1e30b8 --- /dev/null +++ b/templ/examples/streaming/main_templ.go @@ -0,0 +1,116 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "fmt" + "net/http" + "time" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Create a channel to send data to the template. + data := make(chan string) + // Run a background process that will take 10 seconds to complete. + go func() { + // Always remember to close the channel. + defer close(data) + for i := 0; i < 10; i++ { + select { + case <-r.Context().Done(): + // Quit early if the client is no longer connected. + return + case <-time.After(time.Second): + // Send a new piece of data to the channel. + data <- fmt.Sprintf("Part %d", i+1) + } + } + }() + + // Pass the channel to the template. + component := Page(data) + + // Serve using the streaming mode of the handler. + templ.Handler(component, templ.WithStreaming()).ServeHTTP(w, r) + }) + http.ListenAndServe("127.0.0.1:8080", nil) +} + +func Page(data chan string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Page

Page

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for d := range data { + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(d) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/streaming/main.templ`, Line: 48, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = templ.Flush().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/suspense/go.mod b/templ/examples/suspense/go.mod new file mode 100644 index 0000000..1633319 --- /dev/null +++ b/templ/examples/suspense/go.mod @@ -0,0 +1,9 @@ +module githbu.com/a-h/templ/examples/suspense + +go 1.23 + +toolchain go1.23.3 + +replace github.com/a-h/templ => ../../ + +require github.com/a-h/templ v0.2.707 diff --git a/templ/examples/suspense/go.sum b/templ/examples/suspense/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/examples/suspense/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/suspense/main.templ b/templ/examples/suspense/main.templ new file mode 100644 index 0000000..f789576 --- /dev/null +++ b/templ/examples/suspense/main.templ @@ -0,0 +1,111 @@ +package main + +import ( + "net/http" + "sync" + "time" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Create a channel to send deferred component renders to the template. + data := make(chan SlotContents) + + // We know there are 3 slots, so start a WaitGround. + var wg sync.WaitGroup + wg.Add(3) + + // Start the async processes. + // Sidebar. + go func() { + defer wg.Done() + time.Sleep(time.Second * 3) + data <- SlotContents{ + Name: "a", + Contents: A(), + } + }() + + // Content. + go func() { + defer wg.Done() + time.Sleep(time.Second * 2) + data <- SlotContents{ + Name: "b", + Contents: B(), + } + }() + + // Footer. + go func() { + defer wg.Done() + time.Sleep(time.Second * 1) + data <- SlotContents{ + Name: "c", + Contents: C(), + } + }() + + // Close the channel when all processes are done. + go func() { + wg.Wait() + close(data) + }() + + // Pass the channel to the template. + component := Page(data) + + // Serve using the streaming mode of the handler. + templ.Handler(component, templ.WithStreaming()).ServeHTTP(w, r) + }) + http.ListenAndServe("127.0.0.1:8080", nil) +} + +type SlotContents struct { + Name string + Contents templ.Component +} + +templ Slot(name string) { + +
Loading { name }...
+
+} + +templ A() { +
Component A.
+} + +templ B() { +
Component B.
+} + +templ C() { +
Component C.
+} + +templ Page(data chan SlotContents) { + + + + Page + + +

Page

+ @templ.Flush() { + + } + for sc := range data { + @templ.Flush() { +
+ @sc.Contents +
+ } + } + + +} diff --git a/templ/examples/suspense/main_templ.go b/templ/examples/suspense/main_templ.go new file mode 100644 index 0000000..4956f13 --- /dev/null +++ b/templ/examples/suspense/main_templ.go @@ -0,0 +1,335 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "net/http" + "sync" + "time" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Create a channel to send deferred component renders to the template. + data := make(chan SlotContents) + + // We know there are 3 slots, so start a WaitGround. + var wg sync.WaitGroup + wg.Add(3) + + // Start the async processes. + // Sidebar. + go func() { + defer wg.Done() + time.Sleep(time.Second * 3) + data <- SlotContents{ + Name: "a", + Contents: A(), + } + }() + + // Content. + go func() { + defer wg.Done() + time.Sleep(time.Second * 2) + data <- SlotContents{ + Name: "b", + Contents: B(), + } + }() + + // Footer. + go func() { + defer wg.Done() + time.Sleep(time.Second * 1) + data <- SlotContents{ + Name: "c", + Contents: C(), + } + }() + + // Close the channel when all processes are done. + go func() { + wg.Wait() + close(data) + }() + + // Pass the channel to the template. + component := Page(data) + + // Serve using the streaming mode of the handler. + templ.Handler(component, templ.WithStreaming()).ServeHTTP(w, r) + }) + http.ListenAndServe("127.0.0.1:8080", nil) +} + +type SlotContents struct { + Name string + Contents templ.Component +} + +func Slot(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Loading ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/suspense/main.templ`, Line: 71, Col: 21} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "...
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func A() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Component A.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func B() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
Component B.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func C() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
Component C.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func Page(data chan SlotContents) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "Page

Page

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var8 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = templ.Flush().Render(templ.WithChildren(ctx, templ_7745c5c3_Var8), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for sc := range data { + templ_7745c5c3_Var9 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = sc.Contents.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = templ.Flush().Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/syntax-and-usage/components/main.go b/templ/examples/syntax-and-usage/components/main.go new file mode 100644 index 0000000..8c09fdb --- /dev/null +++ b/templ/examples/syntax-and-usage/components/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "context" + "fmt" + "html" + "io" + "os" + + "github.com/a-h/templ" +) + +func main() { + ctx := context.Background() + list([]string{"a", "b", "c"}).Render(ctx, os.Stdout) + codeList([]string{"A", "B", "C"}).Render(ctx, os.Stdout) +} + +func codeList(items []string) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + if _, err = io.WriteString(w, "
    "); err != nil { + return + } + for _, item := range items { + if _, err = io.WriteString(w, fmt.Sprintf("
  1. %s
  2. ", html.EscapeString(item))); err != nil { + return + } + } + if _, err = io.WriteString(w, "
"); err != nil { + return + } + return nil + }) +} diff --git a/templ/examples/syntax-and-usage/components/templsyntax.templ b/templ/examples/syntax-and-usage/components/templsyntax.templ new file mode 100644 index 0000000..02ec2de --- /dev/null +++ b/templ/examples/syntax-and-usage/components/templsyntax.templ @@ -0,0 +1,9 @@ +package main + +templ list(items []string) { +
    + for _, item := range items { +
  1. { item }
  2. + } +
+} diff --git a/templ/examples/syntax-and-usage/components/templsyntax_templ.go b/templ/examples/syntax-and-usage/components/templsyntax_templ.go new file mode 100644 index 0000000..da083c0 --- /dev/null +++ b/templ/examples/syntax-and-usage/components/templsyntax_templ.go @@ -0,0 +1,63 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package main + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func list(items []string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, item := range items { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
  1. ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(item) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/examples/syntax-and-usage/components/templsyntax.templ`, Line: 6, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
  2. ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/typescript/README.md b/templ/examples/typescript/README.md new file mode 100644 index 0000000..59a7a70 --- /dev/null +++ b/templ/examples/typescript/README.md @@ -0,0 +1,53 @@ +# Pass Go data to TypeScript + +This demonstrates how to bundle TypeScript code, and use it in a templ project. + +The TypeScript code is bundled using `esbuild`, with templ used to serve HTML. + +The code demonstrates application of `onclick` event handlers, and how to pass data from Go to TypeScript. + +This demo passes data from server-side Go code to TypeScript code by placing the data in ` + + + + @templ.JSONScript("scriptData", scriptData) + + + +} diff --git a/templ/examples/typescript/components/index_templ.go b/templ/examples/typescript/components/index_templ.go new file mode 100644 index 0000000..befe815 --- /dev/null +++ b/templ/examples/typescript/components/index_templ.go @@ -0,0 +1,65 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +type Data struct { + Message string `json:"msg"` +} + +func Page(attributeData Data, scriptData Data) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Script usage") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSONScript("scriptData", scriptData).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/examples/typescript/go.mod b/templ/examples/typescript/go.mod new file mode 100644 index 0000000..4ff6ca6 --- /dev/null +++ b/templ/examples/typescript/go.mod @@ -0,0 +1,9 @@ +module github.com/a-h/templ/examples/typescript + +go 1.23 + +toolchain go1.23.3 + +replace github.com/a-h/templ => ../../ + +require github.com/a-h/templ v0.0.0-00010101000000-000000000000 diff --git a/templ/examples/typescript/go.sum b/templ/examples/typescript/go.sum new file mode 100644 index 0000000..5a8d551 --- /dev/null +++ b/templ/examples/typescript/go.sum @@ -0,0 +1,2 @@ +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= diff --git a/templ/examples/typescript/main.go b/templ/examples/typescript/main.go new file mode 100644 index 0000000..c105f9a --- /dev/null +++ b/templ/examples/typescript/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/a-h/templ" + "github.com/a-h/templ/examples/typescript/components" +) + +func main() { + mux := http.NewServeMux() + // Serve the JS bundle. + mux.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets")))) + + // Serve the page. + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + // Create random server-side data. + attributeData := components.Data{ + Message: fmt.Sprintf("Hello, from the attribute data"), + } + scriptData := components.Data{ + Message: fmt.Sprintf("Hello, from the script data"), + } + templ.Handler(components.Page(attributeData, scriptData)).ServeHTTP(w, r) + }) + + fmt.Println("Listening on http://localhost:8080") + http.ListenAndServe("localhost:8080", mux) +} diff --git a/templ/examples/typescript/ts/package-lock.json b/templ/examples/typescript/ts/package-lock.json new file mode 100644 index 0000000..1e9fcd8 --- /dev/null +++ b/templ/examples/typescript/ts/package-lock.json @@ -0,0 +1,436 @@ +{ + "name": "ts", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ts", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "esbuild": "0.21.3", + "typescript": "^5.4.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.3.tgz", + "integrity": "sha512-yTgnwQpFVYfvvo4SvRFB0SwrW8YjOxEoT7wfMT7Ol5v7v5LDNvSGo67aExmxOb87nQNeWPVvaGBNfQ7BXcrZ9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.3.tgz", + "integrity": "sha512-bviJOLMgurLJtF1/mAoJLxDZDL6oU5/ztMHnJQRejbJrSc9FFu0QoUoFhvi6qSKJEw9y5oGyvr9fuDtzJ30rNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.3.tgz", + "integrity": "sha512-c+ty9necz3zB1Y+d/N+mC6KVVkGUUOcm4ZmT5i/Fk5arOaY3i6CA3P5wo/7+XzV8cb4GrI/Zjp8NuOQ9Lfsosw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.3.tgz", + "integrity": "sha512-JReHfYCRK3FVX4Ra+y5EBH1b9e16TV2OxrPAvzMsGeES0X2Ndm9ImQRI4Ket757vhc5XBOuGperw63upesclRw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.3.tgz", + "integrity": "sha512-U3fuQ0xNiAkXOmQ6w5dKpEvXQRSpHOnbw7gEfHCRXPeTKW9sBzVck6C5Yneb8LfJm0l6le4NQfkNPnWMSlTFUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.3.tgz", + "integrity": "sha512-3m1CEB7F07s19wmaMNI2KANLcnaqryJxO1fXHUV5j1rWn+wMxdUYoPyO2TnAbfRZdi7ADRwJClmOwgT13qlP3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.3.tgz", + "integrity": "sha512-fsNAAl5pU6wmKHq91cHWQT0Fz0vtyE1JauMzKotrwqIKAswwP5cpHUCxZNSTuA/JlqtScq20/5KZ+TxQdovU/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.3.tgz", + "integrity": "sha512-tci+UJ4zP5EGF4rp8XlZIdq1q1a/1h9XuronfxTMCNBslpCtmk97Q/5qqy1Mu4zIc0yswN/yP/BLX+NTUC1bXA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.3.tgz", + "integrity": "sha512-f6kz2QpSuyHHg01cDawj0vkyMwuIvN62UAguQfnNVzbge2uWLhA7TCXOn83DT0ZvyJmBI943MItgTovUob36SQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.3.tgz", + "integrity": "sha512-vvG6R5g5ieB4eCJBQevyDMb31LMHthLpXTc2IGkFnPWS/GzIFDnaYFp558O+XybTmYrVjxnryru7QRleJvmZ6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.3.tgz", + "integrity": "sha512-HjCWhH7K96Na+66TacDLJmOI9R8iDWDDiqe17C7znGvvE4sW1ECt9ly0AJ3dJH62jHyVqW9xpxZEU1jKdt+29A==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.3.tgz", + "integrity": "sha512-BGpimEccmHBZRcAhdlRIxMp7x9PyJxUtj7apL2IuoG9VxvU/l/v1z015nFs7Si7tXUwEsvjc1rOJdZCn4QTU+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.3.tgz", + "integrity": "sha512-5rMOWkp7FQGtAH3QJddP4w3s47iT20hwftqdm7b+loe95o8JU8ro3qZbhgMRy0VuFU0DizymF1pBKkn3YHWtsw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.3.tgz", + "integrity": "sha512-h0zj1ldel89V5sjPLo5H1SyMzp4VrgN1tPkN29TmjvO1/r0MuMRwJxL8QY05SmfsZRs6TF0c/IDH3u7XYYmbAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.3.tgz", + "integrity": "sha512-dkAKcTsTJ+CRX6bnO17qDJbLoW37npd5gSNtSzjYQr0svghLJYGYB0NF1SNcU1vDcjXLYS5pO4qOW4YbFama4A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.3.tgz", + "integrity": "sha512-vnD1YUkovEdnZWEuMmy2X2JmzsHQqPpZElXx6dxENcIwTu+Cu5ERax6+Ke1QsE814Zf3c6rxCfwQdCTQ7tPuXA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.3.tgz", + "integrity": "sha512-IOXOIm9WaK7plL2gMhsWJd+l2bfrhfilv0uPTptoRoSb2p09RghhQQp9YY6ZJhk/kqmeRt6siRdMSLLwzuT0KQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.3.tgz", + "integrity": "sha512-uTgCwsvQ5+vCQnqM//EfDSuomo2LhdWhFPS8VL8xKf+PKTCrcT/2kPPoWMTs22aB63MLdGMJiE3f1PHvCDmUOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.3.tgz", + "integrity": "sha512-vNAkR17Ub2MgEud2Wag/OE4HTSI6zlb291UYzHez/psiKarp0J8PKGDnAhMBcHFoOHMXHfExzmjMojJNbAStrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.3.tgz", + "integrity": "sha512-W8H9jlGiSBomkgmouaRoTXo49j4w4Kfbl6I1bIdO/vT0+0u4f20ko3ELzV3hPI6XV6JNBVX+8BC+ajHkvffIJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.3.tgz", + "integrity": "sha512-EjEomwyLSCg8Ag3LDILIqYCZAq/y3diJ04PnqGRgq8/4O3VNlXyMd54j/saShaN4h5o5mivOjAzmU6C3X4v0xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.3.tgz", + "integrity": "sha512-WGiE/GgbsEwR33++5rzjiYsKyHywE8QSZPF7Rfx9EBfK3Qn3xyR6IjyCr5Uk38Kg8fG4/2phN7sXp4NPWd3fcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.3.tgz", + "integrity": "sha512-xRxC0jaJWDLYvcUvjQmHCJSfMrgmUuvsoXgDeU/wTorQ1ngDdUBuFtgY3W1Pc5sprGAvZBtWdJX7RPg/iZZUqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.3.tgz", + "integrity": "sha512-Kgq0/ZsAPzKrbOjCQcjoSmPoWhlcVnGAUo7jvaLHoxW1Drto0KGkR1xBNg2Cp43b9ImvxmPEJZ9xkfcnqPsfBw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.3", + "@esbuild/android-arm": "0.21.3", + "@esbuild/android-arm64": "0.21.3", + "@esbuild/android-x64": "0.21.3", + "@esbuild/darwin-arm64": "0.21.3", + "@esbuild/darwin-x64": "0.21.3", + "@esbuild/freebsd-arm64": "0.21.3", + "@esbuild/freebsd-x64": "0.21.3", + "@esbuild/linux-arm": "0.21.3", + "@esbuild/linux-arm64": "0.21.3", + "@esbuild/linux-ia32": "0.21.3", + "@esbuild/linux-loong64": "0.21.3", + "@esbuild/linux-mips64el": "0.21.3", + "@esbuild/linux-ppc64": "0.21.3", + "@esbuild/linux-riscv64": "0.21.3", + "@esbuild/linux-s390x": "0.21.3", + "@esbuild/linux-x64": "0.21.3", + "@esbuild/netbsd-x64": "0.21.3", + "@esbuild/openbsd-x64": "0.21.3", + "@esbuild/sunos-x64": "0.21.3", + "@esbuild/win32-arm64": "0.21.3", + "@esbuild/win32-ia32": "0.21.3", + "@esbuild/win32-x64": "0.21.3" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/templ/examples/typescript/ts/package.json b/templ/examples/typescript/ts/package.json new file mode 100644 index 0000000..930fba6 --- /dev/null +++ b/templ/examples/typescript/ts/package.json @@ -0,0 +1,15 @@ +{ + "name": "ts", + "version": "1.0.0", + "description": "TypeScript templ example.", + "scripts": { + "build": "esbuild --bundle --minify --outfile=../assets/js/index.js ./src/index.ts", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "esbuild": "0.21.3", + "typescript": "^5.4.5" + } +} diff --git a/templ/examples/typescript/ts/src/index.ts b/templ/examples/typescript/ts/src/index.ts new file mode 100644 index 0000000..7b1def5 --- /dev/null +++ b/templ/examples/typescript/ts/src/index.ts @@ -0,0 +1,34 @@ +// You can use npm install to add additional packages. +// And import them in this file. +// esbuild will bundle them into the final output. + +interface Data { + msg: string; +} + +function setupAttributeAlerter() { + const alerter = document.querySelector("#attributeAlerter"); + if (!alerter) { + return; + } + alerter.addEventListener("click", (_event: Event) => { + const dataAttr = alerter?.getAttribute('alert-data') ?? '{}'; + const data: Data = JSON.parse(dataAttr); + alert(data.msg); + }) +} + +function setupScriptAlerter() { + const alerter = document.querySelector("#scriptAlerter"); + if (!alerter) { + return; + } + alerter.addEventListener("click", (_event: Event) => { + const dataContent = document?.getElementById('scriptData')?.textContent ?? '{}'; + const data: Data = JSON.parse(dataContent); + alert(data.msg); + }) +} + +setupAttributeAlerter(); +setupScriptAlerter(); diff --git a/templ/flake.lock b/templ/flake.lock new file mode 100644 index 0000000..c94b891 --- /dev/null +++ b/templ/flake.lock @@ -0,0 +1,102 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735412871, + "narHash": "sha256-Qoz0ow6jDGUIBHxduc7Y1cjYFS71tvEGJV5Src/mj98=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9f94733f93e4fe6e82f516efae007096e4ab5a21", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1735471104, + "narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "gitignore": "gitignore", + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable", + "xc": "xc" + } + }, + "xc": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724404748, + "narHash": "sha256-p6rXzNiDm2uBvO1MLzC5pJp/0zRNzj/snBzZI0ce62s=", + "owner": "joerdav", + "repo": "xc", + "rev": "960ff9f109d47a19122cfb015721a76e3a0f23a2", + "type": "github" + }, + "original": { + "owner": "joerdav", + "repo": "xc", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/templ/flake.nix b/templ/flake.nix new file mode 100644 index 0000000..256c6ee --- /dev/null +++ b/templ/flake.nix @@ -0,0 +1,84 @@ +{ + description = "templ"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; + gitignore = { + url = "github:hercules-ci/gitignore.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + xc = { + url = "github:joerdav/xc"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, nixpkgs-unstable, gitignore, xc }: + let + allSystems = [ + "x86_64-linux" # 64-bit Intel/AMD Linux + "aarch64-linux" # 64-bit ARM Linux + "x86_64-darwin" # 64-bit Intel macOS + "aarch64-darwin" # 64-bit ARM macOS + ]; + forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f { + inherit system; + pkgs = import nixpkgs { inherit system; }; + pkgs-unstable = import nixpkgs-unstable { inherit system; }; + }); + in + { + packages = forAllSystems ({ system, pkgs, ... }: + rec { + default = templ; + + templ = pkgs.buildGo123Module { + name = "templ"; + subPackages = [ "cmd/templ" ]; + src = gitignore.lib.gitignoreSource ./.; + vendorHash = "sha256-OPADot7Lkn9IBjFCfbrqs3es3F6QnWNjSOHxONjG4MM="; + CGO_ENABLED = 0; + flags = [ + "-trimpath" + ]; + ldflags = [ + "-s" + "-w" + "-extldflags -static" + ]; + }; + }); + + # `nix develop` provides a shell containing development tools. + devShell = forAllSystems ({ system, pkgs, pkgs-unstable, ... }: + pkgs.mkShell { + buildInputs = [ + pkgs.golangci-lint + pkgs.cosign # Used to sign container images. + pkgs.esbuild # Used to package JS examples. + pkgs.go + pkgs-unstable.gopls + pkgs.goreleaser + pkgs.gotestsum + pkgs.ko # Used to build Docker images. + pkgs.nodejs # Used to build templ-docs. + xc.packages.${system}.xc + ]; + }); + + # This flake outputs an overlay that can be used to add templ and + # templ-docs to nixpkgs as per https://templ.guide/quick-start/installation/#nix + # + # Example usage: + # + # nixpkgs.overlays = [ + # inputs.templ.overlays.default + # ]; + overlays.default = final: prev: { + templ = self.packages.${final.stdenv.system}.templ; + templ-docs = self.packages.${final.stdenv.system}.templ-docs; + }; + }; +} + diff --git a/templ/flush.go b/templ/flush.go new file mode 100644 index 0000000..56d7d3a --- /dev/null +++ b/templ/flush.go @@ -0,0 +1,36 @@ +package templ + +import ( + "context" + "io" +) + +// Flush flushes the output buffer after all its child components have been rendered. +func Flush() FlushComponent { + return FlushComponent{} +} + +type FlushComponent struct { +} + +type flusherError interface { + Flush() error +} + +type flusher interface { + Flush() +} + +func (f FlushComponent) Render(ctx context.Context, w io.Writer) (err error) { + if err = GetChildren(ctx).Render(ctx, w); err != nil { + return err + } + switch w := w.(type) { + case flusher: + w.Flush() + return nil + case flusherError: + return w.Flush() + } + return nil +} diff --git a/templ/flush_test.go b/templ/flush_test.go new file mode 100644 index 0000000..5b046cf --- /dev/null +++ b/templ/flush_test.go @@ -0,0 +1,126 @@ +package templ + +import ( + "context" + "fmt" + "io" + "strings" + "testing" +) + +type flushableErrorWriter struct { + lastFlushPos int + pos int + sb strings.Builder + flushedSections []string +} + +func (f *flushableErrorWriter) Write(p []byte) (n int, err error) { + n, err = f.sb.Write(p) + if err != nil { + return + } + if n < len(p) { + err = io.ErrShortWrite + } + f.pos += n + return +} + +func (f *flushableErrorWriter) Flush() error { + f.flushedSections = append(f.flushedSections, f.sb.String()[f.lastFlushPos:f.pos]) + f.lastFlushPos = f.pos + return nil +} + +type flushableWriter struct { + lastFlushPos int + pos int + sb strings.Builder + flushedSections []string +} + +func (f *flushableWriter) Write(p []byte) (n int, err error) { + n, err = f.sb.Write(p) + if err != nil { + return + } + if n < len(p) { + err = io.ErrShortWrite + } + f.pos += n + return +} + +func (f *flushableWriter) Flush() { + f.flushedSections = append(f.flushedSections, f.sb.String()[f.lastFlushPos:f.pos]) + f.lastFlushPos = f.pos +} + +func TestFlush(t *testing.T) { + t.Run("errors in child components are propagated", func(t *testing.T) { + expectedErr := fmt.Errorf("test error") + child := ComponentFunc(func(ctx context.Context, w io.Writer) error { + return expectedErr + }) + + sb := new(strings.Builder) + ctx := WithChildren(context.Background(), child) + + err := Flush().Render(ctx, sb) + if err == nil { + t.Fatalf("expected an error, got nil") + } + if err != expectedErr { + t.Fatalf("expected error to be %v, got %v", expectedErr, err) + } + }) + t.Run("can render to a flushable error writer", func(t *testing.T) { + child := ComponentFunc(func(ctx context.Context, w io.Writer) error { + _, err := w.Write([]byte("hello")) + return err + }) + + b := &flushableErrorWriter{} + ctx := WithChildren(context.Background(), child) + + // Render the FlushComponent to the buffer + if err := Flush().Render(ctx, b); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if len(b.flushedSections) != 1 { + t.Fatalf("expected 1 flushed section, got %d", len(b.flushedSections)) + } + if b.flushedSections[0] != "hello" { + t.Fatalf("expected flushed section to be 'hello', got %q", b.flushedSections[0]) + } + }) + t.Run("can render to a flushable writer", func(t *testing.T) { + child := ComponentFunc(func(ctx context.Context, w io.Writer) error { + _, err := w.Write([]byte("hello")) + return err + }) + + b := &flushableWriter{} + ctx := WithChildren(context.Background(), child) + + // Render the FlushComponent to the buffer + if err := Flush().Render(ctx, b); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if len(b.flushedSections) != 1 { + t.Fatalf("expected 1 flushed section, got %d", len(b.flushedSections)) + } + if b.flushedSections[0] != "hello" { + t.Fatalf("expected flushed section to be 'hello', got %q", b.flushedSections[0]) + } + }) + t.Run("non-flushable streams are a no-op", func(t *testing.T) { + sb := new(strings.Builder) + if err := Flush().Render(context.Background(), sb); err != nil { + t.Fatalf("expected no error, got %v", err) + } + }) +} diff --git a/templ/generator/generator.go b/templ/generator/generator.go new file mode 100644 index 0000000..c248298 --- /dev/null +++ b/templ/generator/generator.go @@ -0,0 +1,1638 @@ +package generator + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "html" + "io" + "path/filepath" + "reflect" + "strconv" + "strings" + "time" + "unicode" + + _ "embed" + + "github.com/a-h/templ/parser/v2" +) + +type GenerateOpt func(g *generator) error + +// WithVersion enables the version to be included in the generated code. +func WithVersion(v string) GenerateOpt { + return func(g *generator) error { + g.options.Version = v + return nil + } +} + +// WithTimestamp enables the generated date to be included in the generated code. +func WithTimestamp(d time.Time) GenerateOpt { + return func(g *generator) error { + g.options.GeneratedDate = d.Format(time.RFC3339) + return nil + } +} + +// WithFileName sets the filename of the templ file in template rendering error messages. +func WithFileName(name string) GenerateOpt { + return func(g *generator) error { + if filepath.IsAbs(name) { + _, g.options.FileName = filepath.Split(name) + return nil + } + g.options.FileName = name + return nil + } +} + +// WithSkipCodeGeneratedComment skips the code generated comment at the top of the file. +// gopls disables edit related functionality for generated files, so the templ LSP may +// wish to skip generation of this comment so that gopls provides expected results. +func WithSkipCodeGeneratedComment() GenerateOpt { + return func(g *generator) error { + g.options.SkipCodeGeneratedComment = true + return nil + } +} + +type GeneratorOutput struct { + Options GeneratorOptions `json:"meta"` + SourceMap *parser.SourceMap `json:"sourceMap"` + Literals []string `json:"literals"` +} + +type GeneratorOptions struct { + // Version of templ. + Version string + // FileName to include in error messages if string expressions return an error. + FileName string + // SkipCodeGeneratedComment skips the code generated comment at the top of the file. + SkipCodeGeneratedComment bool + // GeneratedDate to include as a comment. + GeneratedDate string +} + +// HasChanged returns true if the generated file should be written to disk, and therefore, also +// requires a recompilation. +func HasChanged(previous, updated GeneratorOutput) bool { + // If generator options have changed, we need to recompile. + if previous.Options.Version != updated.Options.Version { + return true + } + if previous.Options.FileName != updated.Options.FileName { + return true + } + if previous.Options.SkipCodeGeneratedComment != updated.Options.SkipCodeGeneratedComment { + return true + } + // We don't check the generated date as it's not used for determining if the file has changed. + // If the number of literals has changed, we need to recompile. + if len(previous.Literals) != len(updated.Literals) { + return true + } + // If the Go code has changed, we need to recompile. + if len(previous.SourceMap.Expressions) != len(updated.SourceMap.Expressions) { + return true + } + for i, prev := range previous.SourceMap.Expressions { + if prev != updated.SourceMap.Expressions[i] { + return true + } + } + return false +} + +// Generate generates Go code from the input template file to w, and returns a map of the location of Go expressions in the template +// to the location of the generated Go code in the output. +func Generate(template parser.TemplateFile, w io.Writer, opts ...GenerateOpt) (op GeneratorOutput, err error) { + g := &generator{ + tf: template, + w: NewRangeWriter(w), + sourceMap: parser.NewSourceMap(), + } + for _, opt := range opts { + if err = opt(g); err != nil { + return + } + } + err = g.generate() + if err != nil { + return op, err + } + op.Options = g.options + op.SourceMap = g.sourceMap + op.Literals = g.w.Literals + return op, nil +} + +type generator struct { + tf parser.TemplateFile + w *RangeWriter + sourceMap *parser.SourceMap + variableID int + childrenVar string + + options GeneratorOptions +} + +func (g *generator) generate() (err error) { + if err = g.writeCodeGeneratedComment(); err != nil { + return + } + if err = g.writeVersionComment(); err != nil { + return + } + if err = g.writeGeneratedDateComment(); err != nil { + return + } + if err = g.writeHeader(); err != nil { + return + } + if err = g.writePackage(); err != nil { + return + } + if err = g.writeImports(); err != nil { + return + } + if err = g.writeTemplateNodes(); err != nil { + return + } + if err = g.writeBlankAssignmentForRuntimeImport(); err != nil { + return + } + return err +} + +// See https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source +// Automatically generated files have a comment in the header that instructs the LSP +// to stop operating. +func (g *generator) writeCodeGeneratedComment() (err error) { + if g.options.SkipCodeGeneratedComment { + // Write an empty comment so that the file is the same shape. + _, err = g.w.Write("//\n\n") + return err + } + _, err = g.w.Write("// Code generated by templ - DO NOT EDIT.\n\n") + return err +} + +func (g *generator) writeVersionComment() (err error) { + if g.options.Version != "" { + _, err = g.w.Write("// templ: version: " + g.options.Version + "\n") + } + return err +} + +func (g *generator) writeGeneratedDateComment() (err error) { + if g.options.GeneratedDate != "" { + _, err = g.w.Write("// templ: generated: " + g.options.GeneratedDate + "\n") + } + return err +} + +func (g *generator) writeHeader() (err error) { + if len(g.tf.Header) == 0 { + return nil + } + for _, n := range g.tf.Header { + if err := g.writeGoExpression(n); err != nil { + return err + } + } + return err +} + +func (g *generator) writePackage() error { + var r parser.Range + var err error + // package ... + if r, err = g.w.Write(g.tf.Package.Expression.Value + "\n\n"); err != nil { + return err + } + g.sourceMap.Add(g.tf.Package.Expression, r) + if _, err = g.w.Write("//lint:file-ignore SA4006 This context is only used if a nested component is present.\n\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeImports() error { + var err error + // Always import templ because it's the interface type of all templates. + if _, err = g.w.Write("import \"github.com/a-h/templ\"\n"); err != nil { + return err + } + if _, err = g.w.Write("import templruntime \"github.com/a-h/templ/runtime\"\n"); err != nil { + return err + } + if _, err = g.w.Write("\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeTemplateNodes() error { + for i := 0; i < len(g.tf.Nodes); i++ { + switch n := g.tf.Nodes[i].(type) { + case parser.TemplateFileGoExpression: + if err := g.writeGoExpression(n); err != nil { + return err + } + case parser.HTMLTemplate: + if err := g.writeTemplate(i, n); err != nil { + return err + } + case parser.CSSTemplate: + if err := g.writeCSS(n); err != nil { + return err + } + case parser.ScriptTemplate: + if err := g.writeScript(n); err != nil { + return err + } + default: + return fmt.Errorf("unknown node type: %v", reflect.TypeOf(n)) + } + } + return nil +} + +func (g *generator) writeCSS(n parser.CSSTemplate) error { + var r parser.Range + var tgtSymbolRange parser.Range + var err error + var indentLevel int + + // func + if r, err = g.w.Write("func "); err != nil { + return err + } + tgtSymbolRange.From = r.From + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // templ.CSSClass { + if _, err = g.w.Write(" templ.CSSClass {\n"); err != nil { + return err + } + { + indentLevel++ + // templ_7745c5c3_CSSBuilder := templruntim.GetBuilder() + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_CSSBuilder := templruntime.GetBuilder()\n"); err != nil { + return err + } + for i := 0; i < len(n.Properties); i++ { + switch p := n.Properties[i].(type) { + case parser.ConstantCSSProperty: + // Constant CSS property values are not sanitized. + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_CSSBuilder.WriteString("+createGoString(p.String(true))+")\n"); err != nil { + return err + } + case parser.ExpressionCSSProperty: + // templ_7745c5c3_CSSBuilder.WriteString(templ.SanitizeCSS('name', p.Expression())) + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`%s`, ", p.Name)); err != nil { + return err + } + if r, err = g.w.Write(p.Value.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(p.Value.Expression, r) + if _, err = g.w.Write(")))\n"); err != nil { + return err + } + default: + return fmt.Errorf("unknown CSS property type: %v", reflect.TypeOf(p)) + } + } + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("templ_7745c5c3_CSSID := templ.CSSID(`%s`, templ_7745c5c3_CSSBuilder.String())\n", n.Name)); err != nil { + return err + } + // return templ.CSS { + if _, err = g.w.WriteIndent(indentLevel, "return templ.ComponentCSSClass{\n"); err != nil { + return err + } + { + indentLevel++ + // ID: templ_7745c5c3_CSSID, + if _, err = g.w.WriteIndent(indentLevel, "ID: templ_7745c5c3_CSSID,\n"); err != nil { + return err + } + // Class: templ.SafeCSS(".cssID{" + templ.CSSBuilder.String() + "}"), + if _, err = g.w.WriteIndent(indentLevel, "Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`),\n"); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + indentLevel-- + } + // } + if r, err = g.w.WriteIndent(indentLevel, "}\n\n"); err != nil { + return err + } + + // Keep a track of symbol ranges for the LSP. + tgtSymbolRange.To = r.To + g.sourceMap.AddSymbolRange(n.Range, tgtSymbolRange) + + return nil +} + +func (g *generator) writeGoExpression(n parser.TemplateFileGoExpression) (err error) { + var tgtSymbolRange parser.Range + + r, err := g.w.Write(n.Expression.Value) + if err != nil { + return err + } + tgtSymbolRange.From = r.From + g.sourceMap.Add(n.Expression, r) + v := n.Expression.Value + lineSlice := strings.Split(v, "\n") + lastLine := lineSlice[len(lineSlice)-1] + if strings.HasPrefix(lastLine, "//") { + if _, err = g.w.WriteIndent(0, "\n"); err != nil { + return err + } + return err + } + if r, err = g.w.WriteIndent(0, "\n\n"); err != nil { + return err + } + + // Keep a track of symbol ranges for the LSP. + tgtSymbolRange.To = r.To + g.sourceMap.AddSymbolRange(n.Expression.Range, tgtSymbolRange) + + return err +} + +func (g *generator) writeTemplBuffer(indentLevel int) (err error) { + // templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)\n"); err != nil { + return err + } + // if !templ_7745c5c3_IsBuffer { + // defer func() { + // templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + // if templ_7745c5c3_Err == nil { + // templ_7745c5c3_Err = templ_7745c5c3_BufErr + // } + // }() + // } + if _, err = g.w.WriteIndent(indentLevel, "if !templ_7745c5c3_IsBuffer {\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "defer func() {\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)\n"); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, "if templ_7745c5c3_Err == nil {\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ_7745c5c3_BufErr\n"); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}()\n"); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + return +} + +func (g *generator) writeTemplate(nodeIdx int, t parser.HTMLTemplate) error { + var r parser.Range + var tgtSymbolRange parser.Range + var err error + var indentLevel int + + // func + if r, err = g.w.Write("func "); err != nil { + return err + } + tgtSymbolRange.From = r.From + // (r *Receiver) Name(params []string) + if r, err = g.w.Write(t.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(t.Expression, r) + // templ.Component { + if _, err = g.w.Write(" templ.Component {\n"); err != nil { + return err + } + indentLevel++ + // return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + if _, err = g.w.WriteIndent(indentLevel, "return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context\n"); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, "if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "return templ_7745c5c3_CtxErr"); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + if err := g.writeTemplBuffer(indentLevel); err != nil { + return err + } + // ctx = templ.InitializeContext(ctx) + if _, err = g.w.WriteIndent(indentLevel, "ctx = templ.InitializeContext(ctx)\n"); err != nil { + return err + } + g.childrenVar = g.createVariableName() + // templ_7745c5c3_Var1 := templ.GetChildren(ctx) + // if templ_7745c5c3_Var1 == nil { + // templ_7745c5c3_Var1 = templ.NopComponent + // } + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("%s := templ.GetChildren(ctx)\n", g.childrenVar)); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("if %s == nil {\n", g.childrenVar)); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("%s = templ.NopComponent\n", g.childrenVar)); err != nil { + return err + } + indentLevel-- + } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + // ctx = templ.ClearChildren(children) + if _, err = g.w.WriteIndent(indentLevel, "ctx = templ.ClearChildren(ctx)\n"); err != nil { + return err + } + // Nodes. + if err = g.writeNodes(indentLevel, stripWhitespace(t.Children), nil); err != nil { + return err + } + // return nil + if _, err = g.w.WriteIndent(indentLevel, "return nil\n"); err != nil { + return err + } + indentLevel-- + } + // }) + if _, err = g.w.WriteIndent(indentLevel, "})\n"); err != nil { + return err + } + indentLevel-- + // } + + // Note: gofmt wants to remove a single empty line at the end of a file + // so we have to make sure we don't output one if this is the last node. + closingBrace := "}\n\n" + if nodeIdx+1 >= len(g.tf.Nodes) { + closingBrace = "}\n" + } + + if r, err = g.w.WriteIndent(indentLevel, closingBrace); err != nil { + return err + } + + // Keep a track of symbol ranges for the LSP. + tgtSymbolRange.To = r.To + g.sourceMap.AddSymbolRange(t.Range, tgtSymbolRange) + + return nil +} + +func stripWhitespace(input []parser.Node) (output []parser.Node) { + for i, n := range input { + if _, isWhiteSpace := n.(parser.Whitespace); !isWhiteSpace { + output = append(output, input[i]) + } + } + return output +} + +func stripLeadingWhitespace(nodes []parser.Node) []parser.Node { + for i := 0; i < len(nodes); i++ { + n := nodes[i] + if _, isWhiteSpace := n.(parser.Whitespace); !isWhiteSpace { + return nodes[i:] + } + } + return []parser.Node{} +} + +func stripTrailingWhitespace(nodes []parser.Node) []parser.Node { + for i := len(nodes) - 1; i >= 0; i-- { + n := nodes[i] + if _, isWhiteSpace := n.(parser.Whitespace); !isWhiteSpace { + return nodes[0 : i+1] + } + } + return []parser.Node{} +} + +func stripLeadingAndTrailingWhitespace(nodes []parser.Node) []parser.Node { + return stripTrailingWhitespace(stripLeadingWhitespace(nodes)) +} + +func (g *generator) writeNodes(indentLevel int, nodes []parser.Node, next parser.Node) error { + for i, curr := range nodes { + var nextNode parser.Node + if i+1 < len(nodes) { + nextNode = nodes[i+1] + } + if nextNode == nil { + nextNode = next + } + if err := g.writeNode(indentLevel, curr, nextNode); err != nil { + return err + } + } + return nil +} + +func (g *generator) writeNode(indentLevel int, current parser.Node, next parser.Node) (err error) { + switch n := current.(type) { + case parser.DocType: + err = g.writeDocType(indentLevel, n) + case parser.Element: + err = g.writeElement(indentLevel, n) + case parser.HTMLComment: + err = g.writeComment(indentLevel, n) + case parser.ChildrenExpression: + err = g.writeChildrenExpression(indentLevel) + case parser.RawElement: + err = g.writeRawElement(indentLevel, n) + case parser.ForExpression: + err = g.writeForExpression(indentLevel, n, next) + case parser.CallTemplateExpression: + err = g.writeCallTemplateExpression(indentLevel, n) + case parser.TemplElementExpression: + err = g.writeTemplElementExpression(indentLevel, n) + case parser.IfExpression: + err = g.writeIfExpression(indentLevel, n, next) + case parser.SwitchExpression: + err = g.writeSwitchExpression(indentLevel, n, next) + case parser.StringExpression: + err = g.writeStringExpression(indentLevel, n.Expression) + case parser.GoCode: + err = g.writeGoCode(indentLevel, n.Expression) + case parser.Whitespace: + err = g.writeWhitespace(indentLevel, n) + case parser.Text: + err = g.writeText(indentLevel, n) + case parser.GoComment: + // Do not render Go comments in the output HTML. + return + default: + return fmt.Errorf("unhandled type: %v", reflect.TypeOf(n)) + } + // Write trailing whitespace, if there is a next node that might need the space. + // If the next node is inline or text, we might need it. + // If the current node is a block element, we don't need it. + needed := (isInlineOrText(current) && isInlineOrText(next)) + if ws, ok := current.(parser.WhitespaceTrailer); ok && needed { + if err := g.writeWhitespaceTrailer(indentLevel, ws.Trailing()); err != nil { + return err + } + } + return +} + +func isInlineOrText(next parser.Node) bool { + // While these are formatted as blocks when they're written in the HTML template. + // They're inline - i.e. there's no whitespace rendered around them at runtime for minification. + if next == nil { + return false + } + switch n := next.(type) { + case parser.IfExpression: + return true + case parser.SwitchExpression: + return true + case parser.ForExpression: + return true + case parser.Element: + return !n.IsBlockElement() + case parser.Text: + return true + case parser.StringExpression: + return true + } + return false +} + +func (g *generator) writeWhitespaceTrailer(indentLevel int, n parser.TrailingSpace) (err error) { + if n == parser.SpaceNone { + return nil + } + // Normalize whitespace for minified output. In HTML, a single space is equivalent to + // any number of spaces, tabs, or newlines. + if n == parser.SpaceVertical { + n = parser.SpaceHorizontal + } + if _, err = g.w.WriteStringLiteral(indentLevel, string(n)); err != nil { + return err + } + return nil +} + +func (g *generator) writeDocType(indentLevel int, n parser.DocType) (err error) { + if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf("", n.Value)); err != nil { + return err + } + return nil +} + +func (g *generator) writeIfExpression(indentLevel int, n parser.IfExpression, nextNode parser.Node) (err error) { + var r parser.Range + // if + if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil { + return err + } + // x == y { + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + { + indentLevel++ + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(n.Then), nextNode); err != nil { + return err + } + indentLevel-- + } + for _, elseIf := range n.ElseIfs { + // } else if { + if _, err = g.w.WriteIndent(indentLevel, `} else if `); err != nil { + return err + } + // x == y { + if r, err = g.w.Write(elseIf.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(elseIf.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + { + indentLevel++ + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(elseIf.Then), nextNode); err != nil { + return err + } + indentLevel-- + } + } + if len(n.Else) > 0 { + // } else { + if _, err = g.w.WriteIndent(indentLevel, `} else {`+"\n"); err != nil { + return err + } + { + indentLevel++ + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(n.Else), nextNode); err != nil { + return err + } + indentLevel-- + } + } + // } + if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeSwitchExpression(indentLevel int, n parser.SwitchExpression, next parser.Node) (err error) { + var r parser.Range + // switch + if _, err = g.w.WriteIndent(indentLevel, `switch `); err != nil { + return err + } + // val + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + + if len(n.Cases) > 0 { + for _, c := range n.Cases { + // case x: + // default: + if r, err = g.w.WriteIndent(indentLevel, c.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(c.Expression, r) + indentLevel++ + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(c.Children), next); err != nil { + return err + } + indentLevel-- + } + } + // } + if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeChildrenExpression(indentLevel int) (err error) { + if _, err = g.w.WriteIndent(indentLevel, fmt.Sprintf("templ_7745c5c3_Err = %s.Render(ctx, templ_7745c5c3_Buffer)\n", g.childrenVar)); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeTemplElementExpression(indentLevel int, n parser.TemplElementExpression) (err error) { + if len(n.Children) == 0 { + return g.writeSelfClosingTemplElementExpression(indentLevel, n) + } + return g.writeBlockTemplElementExpression(indentLevel, n) +} + +func (g *generator) writeBlockTemplElementExpression(indentLevel int, n parser.TemplElementExpression) (err error) { + var r parser.Range + childrenName := g.createVariableName() + if _, err = g.w.WriteIndent(indentLevel, childrenName+" := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {\n"); err != nil { + return err + } + indentLevel++ + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context\n"); err != nil { + return err + } + if err := g.writeTemplBuffer(indentLevel); err != nil { + return err + } + // ctx = templ.InitializeContext(ctx) + if _, err = g.w.WriteIndent(indentLevel, "ctx = templ.InitializeContext(ctx)\n"); err != nil { + return err + } + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(n.Children), nil); err != nil { + return err + } + // return nil + if _, err = g.w.WriteIndent(indentLevel, "return nil\n"); err != nil { + return err + } + indentLevel-- + if _, err = g.w.WriteIndent(indentLevel, "})\n"); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, `templ_7745c5c3_Err = `); err != nil { + return err + } + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // .Render(templ.WithChildren(ctx, children), templ_7745c5c3_Buffer) + if _, err = g.w.Write(".Render(templ.WithChildren(ctx, " + childrenName + "), templ_7745c5c3_Buffer)\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeSelfClosingTemplElementExpression(indentLevel int, n parser.TemplElementExpression) (err error) { + if _, err = g.w.WriteIndent(indentLevel, `templ_7745c5c3_Err = `); err != nil { + return err + } + // Template expression. + var r parser.Range + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // .Render(ctx, templ_7745c5c3_Buffer) + if _, err = g.w.Write(".Render(ctx, templ_7745c5c3_Buffer)\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeCallTemplateExpression(indentLevel int, n parser.CallTemplateExpression) (err error) { + if _, err = g.w.WriteIndent(indentLevel, `templ_7745c5c3_Err = `); err != nil { + return err + } + // Template expression. + var r parser.Range + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // .Render(ctx, templ_7745c5c3_Buffer) + if _, err = g.w.Write(".Render(ctx, templ_7745c5c3_Buffer)\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeForExpression(indentLevel int, n parser.ForExpression, next parser.Node) (err error) { + var r parser.Range + // for + if _, err = g.w.WriteIndent(indentLevel, `for `); err != nil { + return err + } + // i, v := range p.Stuff + if r, err = g.w.Write(n.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(n.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + // Children. + indentLevel++ + if err = g.writeNodes(indentLevel, stripLeadingAndTrailingWhitespace(n.Children), next); err != nil { + return err + } + indentLevel-- + // } + if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeErrorHandler(indentLevel int) (err error) { + _, err = g.w.WriteIndent(indentLevel, "if templ_7745c5c3_Err != nil {\n") + if err != nil { + return err + } + indentLevel++ + _, err = g.w.WriteIndent(indentLevel, "return templ_7745c5c3_Err\n") + if err != nil { + return err + } + indentLevel-- + _, err = g.w.WriteIndent(indentLevel, "}\n") + if err != nil { + return err + } + return err +} + +func (g *generator) writeExpressionErrorHandler(indentLevel int, expression parser.Expression) (err error) { + _, err = g.w.WriteIndent(indentLevel, "if templ_7745c5c3_Err != nil {\n") + if err != nil { + return err + } + indentLevel++ + line := int(expression.Range.To.Line + 1) + col := int(expression.Range.To.Col) + _, err = g.w.WriteIndent(indentLevel, "return templ.Error{Err: templ_7745c5c3_Err, FileName: "+createGoString(g.options.FileName)+", Line: "+strconv.Itoa(line)+", Col: "+strconv.Itoa(col)+"}\n") + if err != nil { + return err + } + indentLevel-- + _, err = g.w.WriteIndent(indentLevel, "}\n") + if err != nil { + return err + } + return err +} + +func copyAttributes(attr []parser.Attribute) []parser.Attribute { + o := make([]parser.Attribute, len(attr)) + for i, a := range attr { + if c, ok := a.(parser.ConditionalAttribute); ok { + c.Then = copyAttributes(c.Then) + c.Else = copyAttributes(c.Else) + o[i] = c + continue + } + o[i] = a + } + return o +} + +func (g *generator) writeElement(indentLevel int, n parser.Element) (err error) { + if len(n.Attributes) == 0 { + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(`<%s>`, html.EscapeString(n.Name))); err != nil { + return err + } + } else { + attrs := copyAttributes(n.Attributes) + // + if err = g.writeElementCSS(indentLevel, attrs); err != nil { + return err + } + // + if err = g.writeElementScript(indentLevel, attrs); err != nil { + return err + } + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, `>`); err != nil { + return err + } + } + // Skip children and close tag for void elements. + if n.IsVoidElement() && len(n.Children) == 0 { + return nil + } + // Children. + if err = g.writeNodes(indentLevel, stripWhitespace(n.Children), nil); err != nil { + return err + } + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(``, html.EscapeString(n.Name))); err != nil { + return err + } + return err +} + +func (g *generator) writeAttributeCSS(indentLevel int, attr parser.ExpressionAttribute) (result parser.ExpressionAttribute, ok bool, err error) { + var r parser.Range + name := html.EscapeString(attr.Name) + if name != "class" { + ok = false + return + } + // Create a class name for the style. + // The expression can either be expecting a templ.Classes call, or an expression that returns + // var templ_7745c5c3_CSSClasses = []any{ + classesName := g.createVariableName() + if _, err = g.w.WriteIndent(indentLevel, "var "+classesName+" = []any{"); err != nil { + return + } + // p.Name() + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return + } + g.sourceMap.Add(attr.Expression, r) + // }\n + if _, err = g.w.Write("}\n"); err != nil { + return + } + // Render the CSS before the element if required. + // templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_CSSClasses...) + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, "+classesName+"...)\n"); err != nil { + return + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return + } + // Rewrite the ExpressionAttribute to point at the new variable. + attr.Expression = parser.Expression{ + Value: "templ.CSSClasses(" + classesName + ").String()", + } + return attr, true, nil +} + +func (g *generator) writeAttributesCSS(indentLevel int, attrs []parser.Attribute) (err error) { + for i := 0; i < len(attrs); i++ { + if attr, ok := attrs[i].(parser.ExpressionAttribute); ok { + attr, ok, err = g.writeAttributeCSS(indentLevel, attr) + if err != nil { + return err + } + if ok { + attrs[i] = attr + } + } + if cattr, ok := attrs[i].(parser.ConditionalAttribute); ok { + err = g.writeAttributesCSS(indentLevel, cattr.Then) + if err != nil { + return err + } + err = g.writeAttributesCSS(indentLevel, cattr.Else) + if err != nil { + return err + } + attrs[i] = cattr + } + } + return nil +} + +func (g *generator) writeElementCSS(indentLevel int, attrs []parser.Attribute) (err error) { + return g.writeAttributesCSS(indentLevel, attrs) +} + +func isScriptAttribute(name string) bool { + for _, prefix := range []string{"on", "hx-on:"} { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} + +func (g *generator) writeElementScript(indentLevel int, attrs []parser.Attribute) (err error) { + var scriptExpressions []string + for _, attr := range attrs { + scriptExpressions = append(scriptExpressions, getAttributeScripts(attr)...) + } + if len(scriptExpressions) == 0 { + return + } + // Render the scripts before the element if required. + // templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, a, b, c) + if _, err = g.w.WriteIndent(indentLevel, "templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, "+strings.Join(scriptExpressions, ", ")+")\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return err +} + +func getAttributeScripts(attr parser.Attribute) (scripts []string) { + if attr, ok := attr.(parser.ConditionalAttribute); ok { + for _, attr := range attr.Then { + scripts = append(scripts, getAttributeScripts(attr)...) + } + for _, attr := range attr.Else { + scripts = append(scripts, getAttributeScripts(attr)...) + } + } + if attr, ok := attr.(parser.ExpressionAttribute); ok { + name := html.EscapeString(attr.Name) + if isScriptAttribute(name) { + scripts = append(scripts, attr.Expression.Value) + } + } + return scripts +} + +func (g *generator) writeBoolConstantAttribute(indentLevel int, attr parser.BoolConstantAttribute) (err error) { + name := html.EscapeString(attr.Name) + if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(` %s`, name)); err != nil { + return err + } + return nil +} + +func (g *generator) writeConstantAttribute(indentLevel int, attr parser.ConstantAttribute) (err error) { + name := html.EscapeString(attr.Name) + value := html.EscapeString(attr.Value) + value = strconv.Quote(value) + value = value[1 : len(value)-1] + if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(` %s=\"%s\"`, name, value)); err != nil { + return err + } + return nil +} + +func (g *generator) writeBoolExpressionAttribute(indentLevel int, attr parser.BoolExpressionAttribute) (err error) { + name := html.EscapeString(attr.Name) + // if + if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil { + return err + } + // x == y + var r parser.Range + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + { + indentLevel++ + if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(` %s`, name)); err != nil { + return err + } + indentLevel-- + } + // } + if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeExpressionAttributeValueURL(indentLevel int, attr parser.ExpressionAttribute) (err error) { + vn := g.createVariableName() + // var vn templ.SafeURL = + if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.SafeURL = "); err != nil { + return err + } + // p.Name() + var r parser.Range + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + if _, err = g.w.Write("\n"); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string("+vn+")))\n"); err != nil { + return err + } + return g.writeErrorHandler(indentLevel) +} + +func (g *generator) writeExpressionAttributeValueScript(indentLevel int, attr parser.ExpressionAttribute) (err error) { + // It's a JavaScript handler, and requires special handling, because we expect a JavaScript expression. + vn := g.createVariableName() + // var vn templ.ComponentScript = + if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" templ.ComponentScript = "); err != nil { + return err + } + // p.Name() + var r parser.Range + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + if _, err = g.w.Write("\n"); err != nil { + return err + } + if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("+vn+".Call)\n"); err != nil { + return err + } + return g.writeErrorHandler(indentLevel) +} + +func (g *generator) writeExpressionAttributeValueDefault(indentLevel int, attr parser.ExpressionAttribute) (err error) { + var r parser.Range + vn := g.createVariableName() + // var vn string + if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" string\n"); err != nil { + return err + } + // vn, templ_7745c5c3_Err = templ.JoinStringErrs( + if _, err = g.w.WriteIndent(indentLevel, vn+", templ_7745c5c3_Err = templ.JoinStringErrs("); err != nil { + return err + } + // p.Name() + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + // ) + if _, err = g.w.Write(")\n"); err != nil { + return err + } + // Attribute expression error handler. + err = g.writeExpressionErrorHandler(indentLevel, attr.Expression) + if err != nil { + return err + } + + // _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(vn) + if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString("+vn+"))\n"); err != nil { + return err + } + return g.writeErrorHandler(indentLevel) +} + +func (g *generator) writeExpressionAttributeValueStyle(indentLevel int, attr parser.ExpressionAttribute) (err error) { + var r parser.Range + vn := g.createVariableName() + // var vn string + if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" string\n"); err != nil { + return err + } + // vn, templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues( + if _, err = g.w.WriteIndent(indentLevel, vn+", templ_7745c5c3_Err = templruntime.SanitizeStyleAttributeValues("); err != nil { + return err + } + // value + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + // ) + if _, err = g.w.Write(")\n"); err != nil { + return err + } + // Attribute expression error handler. + err = g.writeExpressionErrorHandler(indentLevel, attr.Expression) + if err != nil { + return err + } + + // _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(vn)) + if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString("+vn+"))\n"); err != nil { + return err + } + return g.writeErrorHandler(indentLevel) +} + +func (g *generator) writeExpressionAttribute(indentLevel int, elementName string, attr parser.ExpressionAttribute) (err error) { + attrName := html.EscapeString(attr.Name) + // Name + if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(` %s=`, attrName)); err != nil { + return err + } + // Open quote. + if _, err = g.w.WriteStringLiteral(indentLevel, `\"`); err != nil { + return err + } + // Value. + if (elementName == "a" && attr.Name == "href") || (elementName == "form" && attr.Name == "action") { + if err := g.writeExpressionAttributeValueURL(indentLevel, attr); err != nil { + return err + } + } else if isScriptAttribute(attr.Name) { + if err := g.writeExpressionAttributeValueScript(indentLevel, attr); err != nil { + return err + } + } else if attr.Name == "style" { + if err := g.writeExpressionAttributeValueStyle(indentLevel, attr); err != nil { + return err + } + } else { + if err := g.writeExpressionAttributeValueDefault(indentLevel, attr); err != nil { + return err + } + } + // Close quote. + if _, err = g.w.WriteStringLiteral(indentLevel, `\"`); err != nil { + return err + } + return nil +} + +func (g *generator) writeSpreadAttributes(indentLevel int, attr parser.SpreadAttributes) (err error) { + // templ.RenderAttributes(ctx, w, spreadAttrs) + if _, err = g.w.WriteIndent(indentLevel, `templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, `); err != nil { + return err + } + // spreadAttrs + var r parser.Range + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + // ) + if _, err = g.w.Write(")\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeConditionalAttribute(indentLevel int, elementName string, attr parser.ConditionalAttribute) (err error) { + // if + if _, err = g.w.WriteIndent(indentLevel, `if `); err != nil { + return err + } + // x == y + var r parser.Range + if r, err = g.w.Write(attr.Expression.Value); err != nil { + return err + } + g.sourceMap.Add(attr.Expression, r) + // { + if _, err = g.w.Write(` {` + "\n"); err != nil { + return err + } + { + indentLevel++ + if err = g.writeElementAttributes(indentLevel, elementName, attr.Then); err != nil { + return err + } + indentLevel-- + } + if len(attr.Else) > 0 { + // } else { + if _, err = g.w.WriteIndent(indentLevel, `} else {`+"\n"); err != nil { + return err + } + { + indentLevel++ + if err = g.writeElementAttributes(indentLevel, elementName, attr.Else); err != nil { + return err + } + indentLevel-- + } + } + // } + if _, err = g.w.WriteIndent(indentLevel, `}`+"\n"); err != nil { + return err + } + return nil +} + +func (g *generator) writeElementAttributes(indentLevel int, name string, attrs []parser.Attribute) (err error) { + for i := 0; i < len(attrs); i++ { + switch attr := attrs[i].(type) { + case parser.BoolConstantAttribute: + err = g.writeBoolConstantAttribute(indentLevel, attr) + case parser.ConstantAttribute: + err = g.writeConstantAttribute(indentLevel, attr) + case parser.BoolExpressionAttribute: + err = g.writeBoolExpressionAttribute(indentLevel, attr) + case parser.ExpressionAttribute: + err = g.writeExpressionAttribute(indentLevel, name, attr) + case parser.SpreadAttributes: + err = g.writeSpreadAttributes(indentLevel, attr) + case parser.ConditionalAttribute: + err = g.writeConditionalAttribute(indentLevel, name, attr) + default: + err = fmt.Errorf("unknown attribute type %s", reflect.TypeOf(attrs[i])) + } + } + return +} + +func (g *generator) writeRawElement(indentLevel int, n parser.RawElement) (err error) { + if len(n.Attributes) == 0 { + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(`<%s>`, html.EscapeString(n.Name))); err != nil { + return err + } + } else { + // + if err = g.writeElementScript(indentLevel, n.Attributes); err != nil { + return err + } + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, `>`); err != nil { + return err + } + } + // Contents. + if err = g.writeText(indentLevel, parser.Text{Value: n.Contents}); err != nil { + return err + } + //
+ if _, err = g.w.WriteStringLiteral(indentLevel, fmt.Sprintf(``, html.EscapeString(n.Name))); err != nil { + return err + } + return err +} + +func (g *generator) writeComment(indentLevel int, c parser.HTMLComment) (err error) { + // + if _, err = g.w.WriteStringLiteral(indentLevel, "-->"); err != nil { + return err + } + return err +} + +func (g *generator) createVariableName() string { + g.variableID++ + return "templ_7745c5c3_Var" + strconv.Itoa(g.variableID) +} + +func (g *generator) writeGoCode(indentLevel int, e parser.Expression) (err error) { + if strings.TrimSpace(e.Value) == "" { + return + } + var r parser.Range + if r, err = g.w.WriteIndent(indentLevel, e.Value+"\n"); err != nil { + return err + } + g.sourceMap.Add(e, r) + return nil +} + +func (g *generator) writeStringExpression(indentLevel int, e parser.Expression) (err error) { + if strings.TrimSpace(e.Value) == "" { + return + } + var r parser.Range + vn := g.createVariableName() + // var vn string + if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" string\n"); err != nil { + return err + } + // vn, templ_7745c5c3_Err = templ.JoinStringErrs( + if _, err = g.w.WriteIndent(indentLevel, vn+", templ_7745c5c3_Err = templ.JoinStringErrs("); err != nil { + return err + } + // p.Name() + if r, err = g.w.Write(e.Value); err != nil { + return err + } + g.sourceMap.Add(e, r) + // ) + if _, err = g.w.Write(")\n"); err != nil { + return err + } + + // String expression error handler. + err = g.writeExpressionErrorHandler(indentLevel, e) + if err != nil { + return err + } + + // _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(vn) + if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString("+vn+"))\n"); err != nil { + return err + } + if err = g.writeErrorHandler(indentLevel); err != nil { + return err + } + return nil +} + +func (g *generator) writeWhitespace(indentLevel int, n parser.Whitespace) (err error) { + if len(n.Value) == 0 { + return + } + // _, err = templ_7745c5c3_Buffer.WriteString(` `) + if _, err = g.w.WriteStringLiteral(indentLevel, " "); err != nil { + return err + } + return nil +} + +func (g *generator) writeText(indentLevel int, n parser.Text) (err error) { + quoted := strconv.Quote(n.Value) + _, err = g.w.WriteStringLiteral(indentLevel, quoted[1:len(quoted)-1]) + return err +} + +func createGoString(s string) string { + var sb strings.Builder + sb.WriteRune('`') + sects := strings.Split(s, "`") + for i := 0; i < len(sects); i++ { + sb.WriteString(sects[i]) + if len(sects) > i+1 { + sb.WriteString("` + \"`\" + `") + } + } + sb.WriteRune('`') + return sb.String() +} + +func (g *generator) writeScript(t parser.ScriptTemplate) error { + var r parser.Range + var tgtSymbolRange parser.Range + var err error + var indentLevel int + + // func + if r, err = g.w.Write("func "); err != nil { + return err + } + tgtSymbolRange.From = r.From + if r, err = g.w.Write(t.Name.Value); err != nil { + return err + } + g.sourceMap.Add(t.Name, r) + // ( + if _, err = g.w.Write("("); err != nil { + return err + } + // Write parameters. + if r, err = g.w.Write(t.Parameters.Value); err != nil { + return err + } + g.sourceMap.Add(t.Parameters, r) + // ) templ.ComponentScript { + if _, err = g.w.Write(") templ.ComponentScript {\n"); err != nil { + return err + } + indentLevel++ + // return templ.ComponentScript{ + if _, err = g.w.WriteIndent(indentLevel, "return templ.ComponentScript{\n"); err != nil { + return err + } + { + indentLevel++ + fn := functionName(t.Name.Value, t.Value) + goFn := createGoString(fn) + // Name: "scriptName", + if _, err = g.w.WriteIndent(indentLevel, "Name: "+goFn+",\n"); err != nil { + return err + } + // Function: `function scriptName(a, b, c){` + `constantScriptValue` + `}`, + prefix := "function " + fn + "(" + stripTypes(t.Parameters.Value) + "){" + body := strings.TrimLeftFunc(t.Value, unicode.IsSpace) + suffix := "}" + if _, err = g.w.WriteIndent(indentLevel, "Function: "+createGoString(prefix+body+suffix)+",\n"); err != nil { + return err + } + // Call: templ.SafeScript(scriptName, a, b, c) + if _, err = g.w.WriteIndent(indentLevel, "Call: templ.SafeScript("+goFn+", "+stripTypes(t.Parameters.Value)+"),\n"); err != nil { + return err + } + // CallInline: templ.SafeScriptInline(scriptName, a, b, c) + if _, err = g.w.WriteIndent(indentLevel, "CallInline: templ.SafeScriptInline("+goFn+", "+stripTypes(t.Parameters.Value)+"),\n"); err != nil { + return err + } + indentLevel-- + } + // } + if _, err = g.w.WriteIndent(indentLevel, "}\n"); err != nil { + return err + } + indentLevel-- + // } + if r, err = g.w.WriteIndent(indentLevel, "}\n\n"); err != nil { + return err + } + + // Keep track of the symbol range for the LSP. + tgtSymbolRange.To = r.To + g.sourceMap.AddSymbolRange(t.Range, tgtSymbolRange) + + return nil +} + +// writeBlankAssignmentForRuntimeImport writes out a blank identifier assignment. +// This ensures that even if the github.com/a-h/templ/runtime package is not used in the generated code, +// the Go compiler will not complain about the unused import. +func (g *generator) writeBlankAssignmentForRuntimeImport() error { + var err error + if _, err = g.w.Write("var _ = templruntime.GeneratedTemplate"); err != nil { + return err + } + return nil +} + +func functionName(name string, body string) string { + h := sha256.New() + h.Write([]byte(body)) + hp := hex.EncodeToString(h.Sum(nil))[0:4] + return "__templ_" + name + "_" + hp +} + +func stripTypes(parameters string) string { + variableNames := []string{} + params := strings.Split(parameters, ",") + for i := 0; i < len(params); i++ { + p := strings.Split(strings.TrimSpace(params[i]), " ") + variableNames = append(variableNames, strings.TrimSpace(p[0])) + } + return strings.Join(variableNames, ", ") +} diff --git a/templ/generator/generator_test.go b/templ/generator/generator_test.go new file mode 100644 index 0000000..fcf139e --- /dev/null +++ b/templ/generator/generator_test.go @@ -0,0 +1,49 @@ +package generator + +import ( + "bytes" + "testing" + + "github.com/a-h/templ/parser/v2" + "github.com/google/go-cmp/cmp" +) + +func TestGeneratorSourceMap(t *testing.T) { + w := new(bytes.Buffer) + g := generator{ + w: NewRangeWriter(w), + sourceMap: parser.NewSourceMap(), + } + invalidExp := parser.TemplateFileGoExpression{ + Expression: parser.Expression{ + Value: "line1\nline2", + }, + } + if err := g.writeGoExpression(invalidExp); err != nil { + t.Fatalf("failed to write Go expression: %v", err) + } + + expected := parser.NewPosition(0, 0, 0) + actual, ok := g.sourceMap.TargetPositionFromSource(0, 0) + if !ok { + t.Errorf("failed to get matching target") + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("unexpected target:\n%v", diff) + } + + withCommentExp := parser.TemplateFileGoExpression{ + Expression: parser.Expression{ + Value: `package main + +// A comment. +templ h1() { +

+} + `, + }, + } + if err := g.writeGoExpression(withCommentExp); err != nil { + t.Fatalf("failed to write Go expression: %v", err) + } +} diff --git a/templ/generator/htmldiff/diff.go b/templ/generator/htmldiff/diff.go new file mode 100644 index 0000000..49aa217 --- /dev/null +++ b/templ/generator/htmldiff/diff.go @@ -0,0 +1,95 @@ +package htmldiff + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + "sync" + + "github.com/a-h/htmlformat" + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func DiffStrings(expected, actual string) (diff string, err error) { + // Format both strings. + var wg sync.WaitGroup + wg.Add(2) + + var errs []error + + // Format expected. + go func() { + defer wg.Done() + e := new(strings.Builder) + err := htmlformat.Fragment(e, strings.NewReader(expected)) + if err != nil { + errs = append(errs, fmt.Errorf("expected html formatting error: %w", err)) + } + expected = e.String() + }() + + // Format actual. + go func() { + defer wg.Done() + a := new(strings.Builder) + err := htmlformat.Fragment(a, strings.NewReader(actual)) + if err != nil { + errs = append(errs, fmt.Errorf("actual html formatting error: %w", err)) + } + actual = a.String() + }() + + // Wait for processing. + wg.Wait() + + return cmp.Diff(expected, actual), errors.Join(errs...) +} + +func Diff(input templ.Component, expected string) (diff string, err error) { + _, diff, err = DiffCtx(context.Background(), input, expected) + return diff, err +} + +func DiffCtx(ctx context.Context, input templ.Component, expected string) (formattedInput, diff string, err error) { + var wg sync.WaitGroup + wg.Add(2) + + var errs []error + + // Format the expected value. + go func() { + defer wg.Done() + e := new(strings.Builder) + err := htmlformat.Fragment(e, strings.NewReader(expected)) + if err != nil { + errs = append(errs, fmt.Errorf("expected html formatting error: %w", err)) + } + expected = e.String() + }() + + // Pipe via the HTML formatter. + actual := new(strings.Builder) + r, w := io.Pipe() + go func() { + defer wg.Done() + err := htmlformat.Fragment(actual, r) + if err != nil { + errs = append(errs, fmt.Errorf("actual html formatting error: %w", err)) + } + }() + + // Render the component. + err = input.Render(ctx, w) + if err != nil { + errs = append(errs, fmt.Errorf("failed to render component: %w", err)) + } + w.Close() + + // Wait for processing. + wg.Wait() + + return actual.String(), cmp.Diff(expected, actual.String()), errors.Join(errs...) +} diff --git a/templ/generator/rangewriter.go b/templ/generator/rangewriter.go new file mode 100644 index 0000000..5c28615 --- /dev/null +++ b/templ/generator/rangewriter.go @@ -0,0 +1,122 @@ +package generator + +import ( + "io" + "strconv" + "strings" + "unicode/utf8" + + "github.com/a-h/templ/parser/v2" +) + +func NewRangeWriter(w io.Writer) *RangeWriter { + return &RangeWriter{ + w: w, + builder: &strings.Builder{}, + } +} + +type RangeWriter struct { + Current parser.Position + inLiteral bool + w io.Writer + + // Extract strings. + index int + builder *strings.Builder + Literals []string +} + +func (rw *RangeWriter) closeLiteral(indent int) (r parser.Range, err error) { + rw.inLiteral = false + rw.index++ + + var sb strings.Builder + sb.WriteString(strings.Repeat("\t", indent)) + sb.WriteString(`templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, `) + sb.WriteString(strconv.Itoa(rw.index)) + sb.WriteString(`, "`) + literal := rw.builder.String() + rw.Literals = append(rw.Literals, literal) + sb.WriteString(literal) + rw.builder.Reset() + sb.WriteString(`")`) + sb.WriteString("\n") + + if _, err := rw.write(sb.String()); err != nil { + return r, err + } + + err = rw.writeErrorHandler(indent) + return +} + +func (rw *RangeWriter) WriteIndent(level int, s string) (r parser.Range, err error) { + if rw.inLiteral { + if _, err = rw.closeLiteral(level); err != nil { + return + } + } + _, err = rw.write(strings.Repeat("\t", level)) + if err != nil { + return + } + return rw.write(s) +} + +func (rw *RangeWriter) WriteStringLiteral(level int, s string) (r parser.Range, err error) { + rw.inLiteral = true + rw.builder.WriteString(s) + return +} + +func (rw *RangeWriter) Write(s string) (r parser.Range, err error) { + if rw.inLiteral { + if _, err = rw.closeLiteral(0); err != nil { + return + } + } + return rw.write(s) +} + +func (rw *RangeWriter) write(s string) (r parser.Range, err error) { + r.From = parser.Position{ + Index: rw.Current.Index, + Line: rw.Current.Line, + Col: rw.Current.Col, + } + utf8Bytes := make([]byte, 4) + for _, c := range s { + rlen := utf8.EncodeRune(utf8Bytes, c) + rw.Current.Col += uint32(rlen) + if c == '\n' { + rw.Current.Line++ + rw.Current.Col = 0 + } + _, err = rw.w.Write(utf8Bytes[:rlen]) + rw.Current.Index += int64(rlen) + if err != nil { + return r, err + } + } + r.To = rw.Current + return r, err +} + +func (rw *RangeWriter) writeErrorHandler(indentLevel int) (err error) { + _, err = rw.WriteIndent(indentLevel, "if templ_7745c5c3_Err != nil {\n") + if err != nil { + return err + } + indentLevel++ + _, err = rw.WriteIndent(indentLevel, "return templ_7745c5c3_Err\n") + if err != nil { + return err + } + indentLevel-- + _, err = rw.WriteIndent(indentLevel, "}\n") + if err != nil { + return err + } + return err +} diff --git a/templ/generator/rangewriter_test.go b/templ/generator/rangewriter_test.go new file mode 100644 index 0000000..05ee8ae --- /dev/null +++ b/templ/generator/rangewriter_test.go @@ -0,0 +1,58 @@ +package generator + +import ( + "bytes" + "testing" + + "github.com/a-h/templ/parser/v2" + "github.com/google/go-cmp/cmp" +) + +func TestRangeWriter(t *testing.T) { + w := new(bytes.Buffer) + rw := NewRangeWriter(w) + t.Run("indices are zero bound", func(t *testing.T) { + if diff := cmp.Diff(parser.NewPosition(0, 0, 0), rw.Current); diff != "" { + t.Error(diff) + } + }) + t.Run("writing characters increases the col position", func(t *testing.T) { + if _, err := rw.Write("abc"); err != nil { + t.Fatalf("failed to write: %v", err) + } + if diff := cmp.Diff(parser.NewPosition(3, 0, 3), rw.Current); diff != "" { + t.Error(diff) + } + }) + t.Run("newline characters implement carriage return", func(t *testing.T) { + if _, err := rw.Write("\n1"); err != nil { + t.Fatalf("failed to write: %v", err) + } + if diff := cmp.Diff(parser.NewPosition(5, 1, 1), rw.Current); diff != "" { + t.Error(diff) + } + }) + t.Run("multi-byte characters count as 3, because that's their UTF8 representation", func(t *testing.T) { + if _, err := rw.Write("\n你"); err != nil { + t.Fatalf("failed to write: %v", err) + } + if diff := cmp.Diff(parser.NewPosition(9, 2, 3), rw.Current); diff != "" { + t.Error(diff) + } + }) + t.Run("a range is returned from each write", func(t *testing.T) { + if _, err := rw.Write("\n"); err != nil { + t.Fatalf("failed to write: %v", err) + } + r, err := rw.Write("test") + if err != nil { + t.Fatalf("expected successful write, got error: %v", err) + } + if diff := cmp.Diff(parser.NewPosition(10, 3, 0), r.From); diff != "" { + t.Errorf("unexpected from:\n%s", diff) + } + if diff := cmp.Diff(parser.NewPosition(14, 3, 4), r.To); diff != "" { + t.Errorf("unexpected to:\n%s", diff) + } + }) +} diff --git a/templ/generator/test-a-href/expected.html b/templ/generator/test-a-href/expected.html new file mode 100644 index 0000000..8599861 --- /dev/null +++ b/templ/generator/test-a-href/expected.html @@ -0,0 +1,3 @@ +Ignored +Sanitized +Unsanitized diff --git a/templ/generator/test-a-href/render_test.go b/templ/generator/test-a-href/render_test.go new file mode 100644 index 0000000..f757924 --- /dev/null +++ b/templ/generator/test-a-href/render_test.go @@ -0,0 +1,23 @@ +package testahref + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-a-href/template.templ b/templ/generator/test-a-href/template.templ new file mode 100644 index 0000000..3088704 --- /dev/null +++ b/templ/generator/test-a-href/template.templ @@ -0,0 +1,7 @@ +package testahref + +templ render() { + Ignored + Sanitized + Unsanitized +} diff --git a/templ/generator/test-a-href/template_templ.go b/templ/generator/test-a-href/template_templ.go new file mode 100644 index 0000000..bdfb357 --- /dev/null +++ b/templ/generator/test-a-href/template_templ.go @@ -0,0 +1,58 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testahref + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Ignored Sanitized Unsanitized") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-attribute-errors/expected.html b/templ/generator/test-attribute-errors/expected.html new file mode 100644 index 0000000..79be24c --- /dev/null +++ b/templ/generator/test-attribute-errors/expected.html @@ -0,0 +1,5 @@ +
    +
  • +
  • +
  • +
diff --git a/templ/generator/test-attribute-errors/render_test.go b/templ/generator/test-attribute-errors/render_test.go new file mode 100644 index 0000000..1dfbad1 --- /dev/null +++ b/templ/generator/test-attribute-errors/render_test.go @@ -0,0 +1,57 @@ +package testattrerrs + +import ( + "bytes" + "context" + _ "embed" + "errors" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + t.Run("can render without error", func(t *testing.T) { + component := TestComponent(nil) + + _, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + t.Run("attribute expressions can return errors", func(t *testing.T) { + errSomethingBad := errors.New("bad error") + + err := TestComponent(errSomethingBad).Render(context.Background(), &bytes.Buffer{}) + if err == nil { + t.Fatalf("expected error, but got nil") + } + + t.Run("the errors are templ errors", func(t *testing.T) { + var templateErr templ.Error + if !errors.As(err, &templateErr) { + t.Fatalf("expected error to be templ.Error, but got %T", err) + } + if templateErr.FileName != `generator/test-attribute-errors/template.templ` { + t.Errorf("expected error in `generator/test-attribute-errors/template.templ`, but got %v", templateErr.FileName) + } + if templateErr.Line != 18 { + t.Errorf("expected error on line 18, but got %v", templateErr.Line) + } + if templateErr.Col != 36 { + t.Errorf("expected error on column 26, but got %v", templateErr.Col) + } + }) + + t.Run("the underlying error can be unwrapped", func(t *testing.T) { + if !errors.Is(err, errSomethingBad) { + t.Errorf("expected error: %v, but got %v", errSomethingBad, err) + } + }) + + }) +} diff --git a/templ/generator/test-attribute-errors/template.templ b/templ/generator/test-attribute-errors/template.templ new file mode 100644 index 0000000..322a005 --- /dev/null +++ b/templ/generator/test-attribute-errors/template.templ @@ -0,0 +1,20 @@ +package testattrerrs + +func funcWithNoError() (s string) { + return "OK" +} + +func funcWithError(in error) (s string, err error) { + if in != nil { + return "", in + } + return "OK2", nil +} + +templ TestComponent(err error) { +
    +
  • +
  • +
  • +
+} diff --git a/templ/generator/test-attribute-errors/template_templ.go b/templ/generator/test-attribute-errors/template_templ.go new file mode 100644 index 0000000..4fbb92d --- /dev/null +++ b/templ/generator/test-attribute-errors/template_templ.go @@ -0,0 +1,90 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testattrerrs + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func funcWithNoError() (s string) { + return "OK" +} + +func funcWithError(in error) (s string, err error) { + if in != nil { + return "", in + } + return "OK2", nil +} + +func TestComponent(err error) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-attribute-escaping/expected.html b/templ/generator/test-attribute-escaping/expected.html new file mode 100644 index 0000000..fcf154d --- /dev/null +++ b/templ/generator/test-attribute-escaping/expected.html @@ -0,0 +1,6 @@ +
+ text +
+
+ +
diff --git a/templ/generator/test-attribute-escaping/render_test.go b/templ/generator/test-attribute-escaping/render_test.go new file mode 100644 index 0000000..bb1fb67 --- /dev/null +++ b/templ/generator/test-attribute-escaping/render_test.go @@ -0,0 +1,23 @@ +package testhtml + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := BasicTemplate(`javascript: alert("xss");`) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-attribute-escaping/template.templ b/templ/generator/test-attribute-escaping/template.templ new file mode 100644 index 0000000..1f1926f --- /dev/null +++ b/templ/generator/test-attribute-escaping/template.templ @@ -0,0 +1,14 @@ +package testhtml + +templ BasicTemplate(url string) { +
+ text +
+
+ +
+} diff --git a/templ/generator/test-attribute-escaping/template_templ.go b/templ/generator/test-attribute-escaping/template_templ.go new file mode 100644 index 0000000..1726588 --- /dev/null +++ b/templ/generator/test-attribute-escaping/template_templ.go @@ -0,0 +1,49 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testhtml + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func BasicTemplate(url string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-call/expected.html b/templ/generator/test-call/expected.html new file mode 100644 index 0000000..bfa1ff9 --- /dev/null +++ b/templ/generator/test-call/expected.html @@ -0,0 +1,8 @@ +
A
+
B
+
C
+
Legacy call style
+
e
+
+
Child content
+
diff --git a/templ/generator/test-call/render_test.go b/templ/generator/test-call/render_test.go new file mode 100644 index 0000000..adf27fe --- /dev/null +++ b/templ/generator/test-call/render_test.go @@ -0,0 +1,23 @@ +package testcall + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := showAll() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-call/template.templ b/templ/generator/test-call/template.templ new file mode 100644 index 0000000..a6c4c9b --- /dev/null +++ b/templ/generator/test-call/template.templ @@ -0,0 +1,44 @@ +package testcall + +templ showAll() { + @a() + @b(c("C")) + @d() + @showOne(e()) + @wrapChildren() { +
Child content
+ } +} + +templ a() { +
A
+} + +templ b(child templ.Component) { +
B
+ @child +} + +templ c(text string) { +
{ text }
+} + +templ d() { +
Legacy call style
+} + +templ e() { + e +} + +templ showOne(component templ.Component) { +
+ @component +
+} + +templ wrapChildren() { +
+ { children... } +
+} diff --git a/templ/generator/test-call/template_templ.go b/templ/generator/test-call/template_templ.go new file mode 100644 index 0000000..181ddfb --- /dev/null +++ b/templ/generator/test-call/template_templ.go @@ -0,0 +1,310 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcall + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func showAll() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = a().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = b(c("C")).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = d().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = showOne(e()).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Child content
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = wrapChildren().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func a() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
A
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func b(child templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
B
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = child.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func c(text string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(text) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-call/template.templ`, Line: 23, Col: 12} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func d() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
Legacy call style
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func e() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "e") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func showOne(component templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = component.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func wrapChildren() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var10.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-cancelled-context/render_test.go b/templ/generator/test-cancelled-context/render_test.go new file mode 100644 index 0000000..306d3f7 --- /dev/null +++ b/templ/generator/test-cancelled-context/render_test.go @@ -0,0 +1,16 @@ +package testcancelledcontext + +import ( + "context" + "io" + "testing" +) + +func Test(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + err := EmptyComponent().Render(ctx, io.Discard) + if err != context.Canceled { + t.Errorf("expected deadline exceeded, got %v (%T)", err, err) + } +} diff --git a/templ/generator/test-cancelled-context/template.templ b/templ/generator/test-cancelled-context/template.templ new file mode 100644 index 0000000..ddb3d4d --- /dev/null +++ b/templ/generator/test-cancelled-context/template.templ @@ -0,0 +1,4 @@ +package testcancelledcontext + +templ EmptyComponent() { +} diff --git a/templ/generator/test-cancelled-context/template_templ.go b/templ/generator/test-cancelled-context/template_templ.go new file mode 100644 index 0000000..3a14872 --- /dev/null +++ b/templ/generator/test-cancelled-context/template_templ.go @@ -0,0 +1,36 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcancelledcontext + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func EmptyComponent() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-complex-attributes/expected.html b/templ/generator/test-complex-attributes/expected.html new file mode 100644 index 0000000..e78916e --- /dev/null +++ b/templ/generator/test-complex-attributes/expected.html @@ -0,0 +1,18 @@ +
+
+
+ + +
+
+ + +
diff --git a/templ/generator/test-complex-attributes/render_test.go b/templ/generator/test-complex-attributes/render_test.go new file mode 100644 index 0000000..e899493 --- /dev/null +++ b/templ/generator/test-complex-attributes/render_test.go @@ -0,0 +1,23 @@ +package testcomplexattributes + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := ComplexAttributes() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-complex-attributes/template.templ b/templ/generator/test-complex-attributes/template.templ new file mode 100644 index 0000000..1f11707 --- /dev/null +++ b/templ/generator/test-complex-attributes/template.templ @@ -0,0 +1,21 @@ +package testcomplexattributes + +templ ComplexAttributes() { +
+
+ + +
+
+ + +
+} diff --git a/templ/generator/test-complex-attributes/template_templ.go b/templ/generator/test-complex-attributes/template_templ.go new file mode 100644 index 0000000..b17fb5f --- /dev/null +++ b/templ/generator/test-complex-attributes/template_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcomplexattributes + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func ComplexAttributes() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-constant-attribute-escaping/expected.html b/templ/generator/test-constant-attribute-escaping/expected.html new file mode 100644 index 0000000..54d5171 --- /dev/null +++ b/templ/generator/test-constant-attribute-escaping/expected.html @@ -0,0 +1,17 @@ +
+ + + + + + + + + + + + + + + +
diff --git a/templ/generator/test-constant-attribute-escaping/render_test.go b/templ/generator/test-constant-attribute-escaping/render_test.go new file mode 100644 index 0000000..2fb2a80 --- /dev/null +++ b/templ/generator/test-constant-attribute-escaping/render_test.go @@ -0,0 +1,23 @@ +package testconstantattributeescaping + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := BasicTemplate() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-constant-attribute-escaping/template.templ b/templ/generator/test-constant-attribute-escaping/template.templ new file mode 100644 index 0000000..e1fc351 --- /dev/null +++ b/templ/generator/test-constant-attribute-escaping/template.templ @@ -0,0 +1,21 @@ +package testconstantattributeescaping + +templ BasicTemplate() { +
+ + + + + + + + + + + + + + + +
+} diff --git a/templ/generator/test-constant-attribute-escaping/template_templ.go b/templ/generator/test-constant-attribute-escaping/template_templ.go new file mode 100644 index 0000000..f92f98c --- /dev/null +++ b/templ/generator/test-constant-attribute-escaping/template_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testconstantattributeescaping + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func BasicTemplate() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-context/expected.html b/templ/generator/test-context/expected.html new file mode 100644 index 0000000..7a2f653 --- /dev/null +++ b/templ/generator/test-context/expected.html @@ -0,0 +1,5 @@ +
    +
  • test
  • +
  • the if passed
  • +
  • the else if passed
  • +
diff --git a/templ/generator/test-context/render_test.go b/templ/generator/test-context/render_test.go new file mode 100644 index 0000000..c662e51 --- /dev/null +++ b/templ/generator/test-context/render_test.go @@ -0,0 +1,26 @@ +package testcontext + +import ( + "context" + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render() + + ctx := context.WithValue(context.Background(), contextKeyName, "test") + + _, diff, err := htmldiff.DiffCtx(ctx, component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-context/template.templ b/templ/generator/test-context/template.templ new file mode 100644 index 0000000..4bc376c --- /dev/null +++ b/templ/generator/test-context/template.templ @@ -0,0 +1,19 @@ +package testcontext + +type contextKey string + +var contextKeyName contextKey = "name" + +templ render() { +
    +
  • { ctx.Value(contextKeyName).(string) }
  • + if ctx.Value(contextKeyName).(string) == "test" { +
  • the if passed
  • + } + if ctx.Value(contextKeyName).(string) != "test" { +
  • the else if failed
  • + } else if ctx.Value(contextKeyName).(string) == "test" { +
  • the else if passed
  • + } +
+} diff --git a/templ/generator/test-context/template_templ.go b/templ/generator/test-context/template_templ.go new file mode 100644 index 0000000..c281fb6 --- /dev/null +++ b/templ/generator/test-context/template_templ.go @@ -0,0 +1,78 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcontext + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +type contextKey string + +var contextKeyName contextKey = "name" + +func render() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(ctx.Value(contextKeyName).(string)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-context/template.templ`, Line: 9, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if ctx.Value(contextKeyName).(string) == "test" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
  • the if passed
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + if ctx.Value(contextKeyName).(string) != "test" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
  • the else if failed
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if ctx.Value(contextKeyName).(string) == "test" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
  • the else if passed
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-css-expression/constants.go b/templ/generator/test-css-expression/constants.go new file mode 100644 index 0000000..b55da9d --- /dev/null +++ b/templ/generator/test-css-expression/constants.go @@ -0,0 +1,3 @@ +package testcssexpression + +const red = "#ff0000" diff --git a/templ/generator/test-css-expression/render_test.go b/templ/generator/test-css-expression/render_test.go new file mode 100644 index 0000000..295b6d8 --- /dev/null +++ b/templ/generator/test-css-expression/render_test.go @@ -0,0 +1,19 @@ +package testcssexpression + +import ( + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +var expected = templ.ComponentCSSClass{ + ID: "className_34fc0328", + Class: templ.SafeCSS(`.className_34fc0328{background-color:#ffffff;max-height:calc(100vh - 170px);color:#ff0000;}`), +} + +func TestCSSExpression(t *testing.T) { + if diff := cmp.Diff(expected, className()); diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-css-expression/template.templ b/templ/generator/test-css-expression/template.templ new file mode 100644 index 0000000..c99a554 --- /dev/null +++ b/templ/generator/test-css-expression/template.templ @@ -0,0 +1,7 @@ +package testcssexpression + +css className() { + background-color: #ffffff; + max-height: calc(100vh - 170px); + color: { red }; +} diff --git a/templ/generator/test-css-expression/template_templ.go b/templ/generator/test-css-expression/template_templ.go new file mode 100644 index 0000000..5923f0c --- /dev/null +++ b/templ/generator/test-css-expression/template_templ.go @@ -0,0 +1,23 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcssexpression + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func className() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`background-color:#ffffff;`) + templ_7745c5c3_CSSBuilder.WriteString(`max-height:calc(100vh - 170px);`) + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`color`, red))) + templ_7745c5c3_CSSID := templ.CSSID(`className`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-css-middleware/expected.html b/templ/generator/test-css-middleware/expected.html new file mode 100644 index 0000000..df6b148 --- /dev/null +++ b/templ/generator/test-css-middleware/expected.html @@ -0,0 +1,3 @@ +
+ Red text +
diff --git a/templ/generator/test-css-middleware/render_test.go b/templ/generator/test-css-middleware/render_test.go new file mode 100644 index 0000000..76a86cc --- /dev/null +++ b/templ/generator/test-css-middleware/render_test.go @@ -0,0 +1,81 @@ +package testcssmiddleware + +import ( + _ "embed" + "fmt" + "net/http/httptest" + "strings" + "sync" + "testing" + + "github.com/a-h/htmlformat" + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +//go:embed expected.html +var expected string + +var expectedCSS = `.red_050e5e03{color:red;} +` + +func Test(t *testing.T) { + var errs []error + var wg sync.WaitGroup + wg.Add(3) + + // Format the expected value. + go func() { + defer wg.Done() + e := new(strings.Builder) + err := htmlformat.Fragment(e, strings.NewReader(expected)) + if err != nil { + errs = append(errs, fmt.Errorf("expected html formatting error: %w", err)) + } + expected = e.String() + }() + + component := render("Red text") + h := templ.Handler(component) + cssmw := templ.NewCSSMiddleware(h, red()) + + // Create the actual value. + var actual string + go func() { + defer wg.Done() + + w := httptest.NewRecorder() + cssmw.ServeHTTP(w, httptest.NewRequest("GET", "/", nil)) + + a := new(strings.Builder) + err := htmlformat.Fragment(a, w.Body) + if err != nil { + errs = append(errs, fmt.Errorf("actual html formatting error: %w", err)) + } + actual = a.String() + }() + + var actualCSS string + go func() { + defer wg.Done() + + w := httptest.NewRecorder() + cssmw.ServeHTTP(w, httptest.NewRequest("GET", "/styles/templ.css", nil)) + + a := new(strings.Builder) + err := htmlformat.Fragment(a, w.Body) + if err != nil { + errs = append(errs, fmt.Errorf("actual html formatting error: %w", err)) + } + actualCSS = a.String() + }() + + wg.Wait() + + if diff := cmp.Diff(expected, actual); diff != "" { + t.Error(diff) + } + if diff := cmp.Diff(expectedCSS, actualCSS); diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-css-middleware/template.templ b/templ/generator/test-css-middleware/template.templ new file mode 100644 index 0000000..6c570d7 --- /dev/null +++ b/templ/generator/test-css-middleware/template.templ @@ -0,0 +1,9 @@ +package testcssmiddleware + +css red() { + color: red; +} + +templ render(s string) { +
{ s }
+} diff --git a/templ/generator/test-css-middleware/template_templ.go b/templ/generator/test-css-middleware/template_templ.go new file mode 100644 index 0000000..b5ef9c4 --- /dev/null +++ b/templ/generator/test-css-middleware/template_templ.go @@ -0,0 +1,81 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcssmiddleware + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func red() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`color:red;`) + templ_7745c5c3_CSSID := templ.CSSID(`red`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func render(s string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var2 = []any{red} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(s) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-css-middleware/template.templ`, Line: 8, Col: 23} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-css-usage/expected.html b/templ/generator/test-css-usage/expected.html new file mode 100644 index 0000000..d488fa1 --- /dev/null +++ b/templ/generator/test-css-usage/expected.html @@ -0,0 +1,36 @@ + +
Style tags are supported
+ +
CSS components are supported
+
Both CSS components and constants are supported
+
Both CSS components and constants are supported
+
Maps can be used to determine if a class should be added or not.
+ +
KV can be used to conditionally set classes.
+
Pseudo attributes and complex class names are supported.
+
+ Class names are HTML escaped. +
+ +
+ CSS components can be used with arguments. +
+ +
+ CSS components can be used with arguments. +
+ +
+ Rotate +
+ diff --git a/templ/generator/test-css-usage/render_test.go b/templ/generator/test-css-usage/render_test.go new file mode 100644 index 0000000..342f692 --- /dev/null +++ b/templ/generator/test-css-usage/render_test.go @@ -0,0 +1,23 @@ +package testcssusage + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := TestComponent() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-css-usage/template.templ b/templ/generator/test-css-usage/template.templ new file mode 100644 index 0000000..0af1f19 --- /dev/null +++ b/templ/generator/test-css-usage/template.templ @@ -0,0 +1,96 @@ +package testcssusage + +import ( + "fmt" + "math" +) + +templ StyleTagsAreSupported() { + +
Style tags are supported
+} + +// CSS components. + +const red = "#00ff00" + +css cssComponentGreen() { + color: { red }; +} + +templ CSSComponentsAreSupported() { +
CSS components are supported
+} + +// Both CSS components and constants are supported. +// Only string names are really required. There is no need to use templ.Class or templ.SafeClass. +templ CSSComponentsAndConstantsAreSupported() { +
Both CSS components and constants are supported
+ // The following is also valid, but not required - you can put the class names in directly. +
Both CSS components and constants are supported
+} + +// Maps can be used to determine if a class should be added or not. +templ MapsCanBeUsedToConditionallySetClasses() { +
Maps can be used to determine if a class should be added or not.
+} + +// The templ.KV function can be used to add a class if a condition is true. + +css d() { + font-size: 12pt; +} + +css e() { + font-size: 14pt; +} + +templ KVCanBeUsedToConditionallySetClasses() { +
KV can be used to conditionally set classes.
+} + +// Pseudo attributes can be used without any special syntax. +templ PseudoAttributesAndComplexClassNamesAreSupported() { +
Pseudo attributes and complex class names are supported.
+} + +// Class names are HTML escaped. +templ ClassNamesAreHTMLEscaped() { +
Class names are HTML escaped.
+} + +// CSS components can be used with arguments. + +css loading(percent int) { + width: { fmt.Sprintf("%d%%", percent) }; +} + +templ CSSComponentsCanBeUsedWithArguments() { +
CSS components can be used with arguments.
+
CSS components can be used with arguments.
+} + +css windVaneRotation(degrees float64) { + transform: { templ.SafeCSSProperty(fmt.Sprintf("rotate(%ddeg)", int(math.Round(degrees)))) }; +} + +templ Rotate(degrees float64) { +
Rotate
+} + +// Combine all tests. +templ TestComponent() { + @StyleTagsAreSupported() + @CSSComponentsAreSupported() + @CSSComponentsAndConstantsAreSupported() + @MapsCanBeUsedToConditionallySetClasses() + @KVCanBeUsedToConditionallySetClasses() + @PseudoAttributesAndComplexClassNamesAreSupported() + @ClassNamesAreHTMLEscaped() + @CSSComponentsCanBeUsedWithArguments() + @Rotate(45) +} diff --git a/templ/generator/test-css-usage/template_templ.go b/templ/generator/test-css-usage/template_templ.go new file mode 100644 index 0000000..210126a --- /dev/null +++ b/templ/generator/test-css-usage/template_templ.go @@ -0,0 +1,588 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcssusage + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import ( + "fmt" + "math" +) + +func StyleTagsAreSupported() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Style tags are supported
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// CSS components. + +const red = "#00ff00" + +func cssComponentGreen() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`color`, red))) + templ_7745c5c3_CSSID := templ.CSSID(`cssComponentGreen`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func CSSComponentsAreSupported() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var3 = []any{cssComponentGreen()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
CSS components are supported
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Both CSS components and constants are supported. +// Only string names are really required. There is no need to use templ.Class or templ.SafeClass. +func CSSComponentsAndConstantsAreSupported() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var6 = []any{cssComponentGreen(), "classA", templ.Class("&&&classB"), templ.SafeClass("classC"), "d e"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
Both CSS components and constants are supported
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 = []any{templ.Classes(cssComponentGreen(), "classA", templ.Class("&&&classB"), templ.SafeClass("classC")), "d e"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "
Both CSS components and constants are supported
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Maps can be used to determine if a class should be added or not. +func MapsCanBeUsedToConditionallySetClasses() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var11 = []any{map[string]bool{"a": true, "b": false, "c": true}} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
Maps can be used to determine if a class should be added or not.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// The templ.KV function can be used to add a class if a condition is true. +func d() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`font-size:12pt;`) + templ_7745c5c3_CSSID := templ.CSSID(`d`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func e() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`font-size:14pt;`) + templ_7745c5c3_CSSID := templ.CSSID(`e`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func KVCanBeUsedToConditionallySetClasses() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var14 = []any{"a", templ.KV("b", false), "c", templ.KV(d(), false), templ.KV(e(), true)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
KV can be used to conditionally set classes.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Pseudo attributes can be used without any special syntax. +func PseudoAttributesAndComplexClassNamesAreSupported() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var17 = []any{"bg-violet-500", "hover:bg-red-600", "hover:bg-sky-700", "text-[#50d71e]", "w-[calc(100%-4rem)"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
Pseudo attributes and complex class names are supported.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Class names are HTML escaped. +func ClassNamesAreHTMLEscaped() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var19 := templ.GetChildren(ctx) + if templ_7745c5c3_Var19 == nil { + templ_7745c5c3_Var19 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var20 = []any{"a\" onClick=\"alert('hello')\""} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var20...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
Class names are HTML escaped.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// CSS components can be used with arguments. +func loading(percent int) templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`width`, fmt.Sprintf("%d%%", percent)))) + templ_7745c5c3_CSSID := templ.CSSID(`loading`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func CSSComponentsCanBeUsedWithArguments() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var22 := templ.GetChildren(ctx) + if templ_7745c5c3_Var22 == nil { + templ_7745c5c3_Var22 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var23 = []any{loading(50)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var23...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
CSS components can be used with arguments.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var25 = []any{loading(100)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var25...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
CSS components can be used with arguments.
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func windVaneRotation(degrees float64) templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`transform`, templ.SafeCSSProperty(fmt.Sprintf("rotate(%ddeg)", int(math.Round(degrees))))))) + templ_7745c5c3_CSSID := templ.CSSID(`windVaneRotation`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func Rotate(degrees float64) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var27 := templ.GetChildren(ctx) + if templ_7745c5c3_Var27 == nil { + templ_7745c5c3_Var27 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var28 = []any{windVaneRotation(degrees)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var28...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
Rotate
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Combine all tests. +func TestComponent() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var30 := templ.GetChildren(ctx) + if templ_7745c5c3_Var30 == nil { + templ_7745c5c3_Var30 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = StyleTagsAreSupported().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = CSSComponentsAreSupported().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = CSSComponentsAndConstantsAreSupported().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = MapsCanBeUsedToConditionallySetClasses().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = KVCanBeUsedToConditionallySetClasses().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = PseudoAttributesAndComplexClassNamesAreSupported().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ClassNamesAreHTMLEscaped().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = CSSComponentsCanBeUsedWithArguments().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = Rotate(45).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-doctype/expected.html b/templ/generator/test-doctype/expected.html new file mode 100644 index 0000000..a15bac3 --- /dev/null +++ b/templ/generator/test-doctype/expected.html @@ -0,0 +1,10 @@ + + + + + + +title + +content + diff --git a/templ/generator/test-doctype/render_test.go b/templ/generator/test-doctype/render_test.go new file mode 100644 index 0000000..e124306 --- /dev/null +++ b/templ/generator/test-doctype/render_test.go @@ -0,0 +1,23 @@ +package testdoctype + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := Layout("title", "content") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-doctype/template.templ b/templ/generator/test-doctype/template.templ new file mode 100644 index 0000000..76f3642 --- /dev/null +++ b/templ/generator/test-doctype/template.templ @@ -0,0 +1,14 @@ +package testdoctype + +templ Layout(title, content string) { + + + + + + + { title } + + { content } + +} diff --git a/templ/generator/test-doctype/template_templ.go b/templ/generator/test-doctype/template_templ.go new file mode 100644 index 0000000..003f7ec --- /dev/null +++ b/templ/generator/test-doctype/template_templ.go @@ -0,0 +1,66 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testdoctype + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Layout(title, content string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-doctype/template.templ`, Line: 10, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(content) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-doctype/template.templ`, Line: 12, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-element-attributes/data.go b/templ/generator/test-element-attributes/data.go new file mode 100644 index 0000000..fb4e9b7 --- /dev/null +++ b/templ/generator/test-element-attributes/data.go @@ -0,0 +1,7 @@ +package testelementattributes + +type person struct { + name string + email string + important bool +} diff --git a/templ/generator/test-element-attributes/expected.html b/templ/generator/test-element-attributes/expected.html new file mode 100644 index 0000000..03680c7 --- /dev/null +++ b/templ/generator/test-element-attributes/expected.html @@ -0,0 +1,30 @@ + +
+ Important +
+ +
+ Unimportant +
+
+ Else +
+
+
+ +

HTMX Wildcard attribute

+ +
+ +
diff --git a/templ/generator/test-element-attributes/render_test.go b/templ/generator/test-element-attributes/render_test.go new file mode 100644 index 0000000..a29da59 --- /dev/null +++ b/templ/generator/test-element-attributes/render_test.go @@ -0,0 +1,28 @@ +package testelementattributes + +import ( + _ "embed" + "testing" + + _ "embed" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(person{ + name: "Luiz Bonfa", + email: "luiz@example.com", + }) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-element-attributes/template.templ b/templ/generator/test-element-attributes/template.templ new file mode 100644 index 0000000..2e31639 --- /dev/null +++ b/templ/generator/test-element-attributes/template.templ @@ -0,0 +1,46 @@ +package testelementattributes + +css important() { + width: 100; +} + +css unimportant() { + width: 50; +} + +templ render(p person) { +
Important
+
Unimportant
+
Else
+
+

HTMX Wildcard attribute

+
+ +
+} diff --git a/templ/generator/test-element-attributes/template_templ.go b/templ/generator/test-element-attributes/template_templ.go new file mode 100644 index 0000000..ec8a8cb --- /dev/null +++ b/templ/generator/test-element-attributes/template_templ.go @@ -0,0 +1,175 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testelementattributes + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func important() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`width:100;`) + templ_7745c5c3_CSSID := templ.CSSID(`important`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func unimportant() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`width:50;`) + templ_7745c5c3_CSSID := templ.CSSID(`unimportant`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func render(p person) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var2 = []any{important()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Important
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 = []any{unimportant} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
Unimportant
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 = []any{important} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 = []any{unimportant} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var7...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
Else

HTMX Wildcard attribute

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-elseif/data.go b/templ/generator/test-elseif/data.go new file mode 100644 index 0000000..b29337c --- /dev/null +++ b/templ/generator/test-elseif/data.go @@ -0,0 +1,8 @@ +package elseif + +type data struct { +} + +func (d data) IsTrue() bool { + return false +} diff --git a/templ/generator/test-elseif/expected.html b/templ/generator/test-elseif/expected.html new file mode 100644 index 0000000..722abff --- /dev/null +++ b/templ/generator/test-elseif/expected.html @@ -0,0 +1,9 @@ +
+ False +
+
+ ElseIf +
+
+ OK +
diff --git a/templ/generator/test-elseif/render_test.go b/templ/generator/test-elseif/render_test.go new file mode 100644 index 0000000..45b81db --- /dev/null +++ b/templ/generator/test-elseif/render_test.go @@ -0,0 +1,23 @@ +package elseif + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(data{}) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-elseif/template.templ b/templ/generator/test-elseif/template.templ new file mode 100644 index 0000000..a571fe4 --- /dev/null +++ b/templ/generator/test-elseif/template.templ @@ -0,0 +1,31 @@ +package elseif + +templ render(d data) { +
+ if d.IsTrue() { + { "True" } + } else if !d.IsTrue() { + { "False" } + } else { + { "Else" } + } +
+
+ if 1 == 2 { + { "If" } + } else if 1 == 1 { + { "ElseIf" } + } +
+
+ if 1 == 2 { + { "If" } + } else if 1 == 3 { + { "ElseIf" } + } else if 1 == 4 { + { "ElseIf" } + } else if 1 == 1 { + { "OK" } + } +
+} diff --git a/templ/generator/test-elseif/template_templ.go b/templ/generator/test-elseif/template_templ.go new file mode 100644 index 0000000..a0243e3 --- /dev/null +++ b/templ/generator/test-elseif/template_templ.go @@ -0,0 +1,145 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package elseif + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(d data) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if d.IsTrue() { + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("True") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 6, Col: 11} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if !d.IsTrue() { + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("False") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 8, Col: 12} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("Else") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 10, Col: 11} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if 1 == 2 { + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("If") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 15, Col: 9} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if 1 == 1 { + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("ElseIf") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 17, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if 1 == 2 { + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs("If") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 22, Col: 9} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if 1 == 3 { + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs("ElseIf") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 24, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if 1 == 4 { + var templ_7745c5c3_Var9 string + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs("ElseIf") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 26, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if 1 == 1 { + var templ_7745c5c3_Var10 string + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs("OK") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-elseif/template.templ`, Line: 28, Col: 9} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-for/expected.html b/templ/generator/test-for/expected.html new file mode 100644 index 0000000..3fd1265 --- /dev/null +++ b/templ/generator/test-for/expected.html @@ -0,0 +1,3 @@ +
a
+
b
+
c
diff --git a/templ/generator/test-for/render_test.go b/templ/generator/test-for/render_test.go new file mode 100644 index 0000000..5935ba0 --- /dev/null +++ b/templ/generator/test-for/render_test.go @@ -0,0 +1,23 @@ +package testfor + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render([]string{"a", "b", "c"}) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-for/template.templ b/templ/generator/test-for/template.templ new file mode 100644 index 0000000..9034171 --- /dev/null +++ b/templ/generator/test-for/template.templ @@ -0,0 +1,7 @@ +package testfor + +templ render(items []string) { + for _, item := range items { +
{ item }
+ } +} diff --git a/templ/generator/test-for/template_templ.go b/templ/generator/test-for/template_templ.go new file mode 100644 index 0000000..b271073 --- /dev/null +++ b/templ/generator/test-for/template_templ.go @@ -0,0 +1,55 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testfor + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(items []string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + for _, item := range items { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(item) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-for/template.templ`, Line: 5, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-form-action/expected.html b/templ/generator/test-form-action/expected.html new file mode 100644 index 0000000..198a1cd --- /dev/null +++ b/templ/generator/test-form-action/expected.html @@ -0,0 +1,3 @@ +
Ignored
+
Sanitized
+
Unsanitized
diff --git a/templ/generator/test-form-action/render_test.go b/templ/generator/test-form-action/render_test.go new file mode 100644 index 0000000..f757924 --- /dev/null +++ b/templ/generator/test-form-action/render_test.go @@ -0,0 +1,23 @@ +package testahref + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-form-action/template.templ b/templ/generator/test-form-action/template.templ new file mode 100644 index 0000000..0ff3802 --- /dev/null +++ b/templ/generator/test-form-action/template.templ @@ -0,0 +1,7 @@ +package testahref + +templ render() { +
Ignored
+
Sanitized
+
Unsanitized
+} diff --git a/templ/generator/test-form-action/template_templ.go b/templ/generator/test-form-action/template_templ.go new file mode 100644 index 0000000..38258df --- /dev/null +++ b/templ/generator/test-form-action/template_templ.go @@ -0,0 +1,58 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testahref + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
Ignored
Sanitized
Unsanitized
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-go-comments/expected.html b/templ/generator/test-go-comments/expected.html new file mode 100644 index 0000000..c46a177 --- /dev/null +++ b/templ/generator/test-go-comments/expected.html @@ -0,0 +1 @@ +

sample content

diff --git a/templ/generator/test-go-comments/render_test.go b/templ/generator/test-go-comments/render_test.go new file mode 100644 index 0000000..b324b85 --- /dev/null +++ b/templ/generator/test-go-comments/render_test.go @@ -0,0 +1,23 @@ +package testcomment + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render("sample content") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-go-comments/template.templ b/templ/generator/test-go-comments/template.templ new file mode 100644 index 0000000..d701c88 --- /dev/null +++ b/templ/generator/test-go-comments/template.templ @@ -0,0 +1,10 @@ +package testcomment + +templ render(content string) { + // This is not rendered. +

{ content }

+ /* + This is also not rendered. + */ + /* Neither is this */ +} diff --git a/templ/generator/test-go-comments/template_templ.go b/templ/generator/test-go-comments/template_templ.go new file mode 100644 index 0000000..0e8bbf6 --- /dev/null +++ b/templ/generator/test-go-comments/template_templ.go @@ -0,0 +1,53 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcomment + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(content string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(content) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-go-comments/template.templ`, Line: 5, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-go-template-in-templ/expected.html b/templ/generator/test-go-template-in-templ/expected.html new file mode 100644 index 0000000..cf99512 --- /dev/null +++ b/templ/generator/test-go-template-in-templ/expected.html @@ -0,0 +1,6 @@ + + + +
Hello, World!
+ + diff --git a/templ/generator/test-go-template-in-templ/render_test.go b/templ/generator/test-go-template-in-templ/render_test.go new file mode 100644 index 0000000..36614f9 --- /dev/null +++ b/templ/generator/test-go-template-in-templ/render_test.go @@ -0,0 +1,22 @@ +package testgotemplates + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func TestExample(t *testing.T) { + component := Example() + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-go-template-in-templ/template.templ b/templ/generator/test-go-template-in-templ/template.templ new file mode 100644 index 0000000..99614ef --- /dev/null +++ b/templ/generator/test-go-template-in-templ/template.templ @@ -0,0 +1,14 @@ +package testgotemplates + +import "html/template" + +var goTemplate = template.Must(template.New("example").Parse("
{{ . }}
")) + +templ Example() { + + + + @templ.FromGoHTML(goTemplate, "Hello, World!") + + +} diff --git a/templ/generator/test-go-template-in-templ/template_templ.go b/templ/generator/test-go-template-in-templ/template_templ.go new file mode 100644 index 0000000..9b00d49 --- /dev/null +++ b/templ/generator/test-go-template-in-templ/template_templ.go @@ -0,0 +1,52 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testgotemplates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "html/template" + +var goTemplate = template.Must(template.New("example").Parse("
{{ . }}
")) + +func Example() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.FromGoHTML(goTemplate, "Hello, World!").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-html-comment/expected.html b/templ/generator/test-html-comment/expected.html new file mode 100644 index 0000000..e4c421b --- /dev/null +++ b/templ/generator/test-html-comment/expected.html @@ -0,0 +1,14 @@ + +

sample content

+ +

second paragraph

+ +

third paragraph

+ + sample content + diff --git a/templ/generator/test-html-comment/render_test.go b/templ/generator/test-html-comment/render_test.go new file mode 100644 index 0000000..b324b85 --- /dev/null +++ b/templ/generator/test-html-comment/render_test.go @@ -0,0 +1,23 @@ +package testcomment + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render("sample content") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-html-comment/template.templ b/templ/generator/test-html-comment/template.templ new file mode 100644 index 0000000..a16c3b1 --- /dev/null +++ b/templ/generator/test-html-comment/template.templ @@ -0,0 +1,22 @@ +package testcomment + +templ render(content string) { + + @paragraph(content) + + @paragraph("second paragraph") + + @paragraph("third paragraph") + + { content } + +} + +templ paragraph(content string) { +

{ content }

+} diff --git a/templ/generator/test-html-comment/template_templ.go b/templ/generator/test-html-comment/template_templ.go new file mode 100644 index 0000000..f333d77 --- /dev/null +++ b/templ/generator/test-html-comment/template_templ.go @@ -0,0 +1,119 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testcomment + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(content string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = paragraph(content).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = paragraph("second paragraph").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = paragraph("third paragraph").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(content) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-html-comment/template.templ`, Line: 16, Col: 16} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func paragraph(content string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(content) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-html-comment/template.templ`, Line: 21, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-html/data.go b/templ/generator/test-html/data.go new file mode 100644 index 0000000..4625d14 --- /dev/null +++ b/templ/generator/test-html/data.go @@ -0,0 +1,6 @@ +package testhtml + +type person struct { + name string + email string +} diff --git a/templ/generator/test-html/expected.html b/templ/generator/test-html/expected.html new file mode 100644 index 0000000..a04251d --- /dev/null +++ b/templ/generator/test-html/expected.html @@ -0,0 +1,11 @@ +
+

Luiz Bonfa

+
+ +
+
+
+
+
+Text diff --git a/templ/generator/test-html/render_test.go b/templ/generator/test-html/render_test.go new file mode 100644 index 0000000..d5d2528 --- /dev/null +++ b/templ/generator/test-html/render_test.go @@ -0,0 +1,26 @@ +package testhtml + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(person{ + name: "Luiz Bonfa", + email: "luiz@example.com", + }) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-html/template.templ b/templ/generator/test-html/template.templ new file mode 100644 index 0000000..4f338ca --- /dev/null +++ b/templ/generator/test-html/template.templ @@ -0,0 +1,14 @@ +package testhtml + +templ render(p person) { +
+

{ p.name }

+
` }> + +
+
+
+
+
+ Text +} diff --git a/templ/generator/test-html/template_templ.go b/templ/generator/test-html/template_templ.go new file mode 100644 index 0000000..aa9d4ea --- /dev/null +++ b/templ/generator/test-html/template_templ.go @@ -0,0 +1,118 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testhtml + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(p person) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(p.name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-html/template.templ`, Line: 5, Col: 14} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

`) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-html/template.templ`, Line: 6, Col: 104} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">


Text") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-if/data.go b/templ/generator/test-if/data.go new file mode 100644 index 0000000..01f9605 --- /dev/null +++ b/templ/generator/test-if/data.go @@ -0,0 +1,8 @@ +package testif + +type data struct { +} + +func (d data) IsTrue() bool { + return true +} diff --git a/templ/generator/test-if/expected.html b/templ/generator/test-if/expected.html new file mode 100644 index 0000000..0ca9514 --- /dev/null +++ b/templ/generator/test-if/expected.html @@ -0,0 +1 @@ +True diff --git a/templ/generator/test-if/render_test.go b/templ/generator/test-if/render_test.go new file mode 100644 index 0000000..08f9635 --- /dev/null +++ b/templ/generator/test-if/render_test.go @@ -0,0 +1,23 @@ +package testif + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(data{}) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-if/template.templ b/templ/generator/test-if/template.templ new file mode 100644 index 0000000..a1621bf --- /dev/null +++ b/templ/generator/test-if/template.templ @@ -0,0 +1,9 @@ +package testif + +templ render(d data) { + if d.IsTrue() { + { "True" } + } else { + { "False" } + } +} diff --git a/templ/generator/test-if/template_templ.go b/templ/generator/test-if/template_templ.go new file mode 100644 index 0000000..b090be8 --- /dev/null +++ b/templ/generator/test-if/template_templ.go @@ -0,0 +1,57 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testif + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(d data) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if d.IsTrue() { + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("True") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-if/template.templ`, Line: 5, Col: 10} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("False") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-if/template.templ`, Line: 7, Col: 11} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-ifelse/data.go b/templ/generator/test-ifelse/data.go new file mode 100644 index 0000000..90abffe --- /dev/null +++ b/templ/generator/test-ifelse/data.go @@ -0,0 +1,8 @@ +package ifelse + +type data struct { +} + +func (d data) IsTrue() bool { + return false +} diff --git a/templ/generator/test-ifelse/expected.html b/templ/generator/test-ifelse/expected.html new file mode 100644 index 0000000..bc59c12 --- /dev/null +++ b/templ/generator/test-ifelse/expected.html @@ -0,0 +1 @@ +False diff --git a/templ/generator/test-ifelse/render_test.go b/templ/generator/test-ifelse/render_test.go new file mode 100644 index 0000000..97fe1ee --- /dev/null +++ b/templ/generator/test-ifelse/render_test.go @@ -0,0 +1,23 @@ +package ifelse + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(data{}) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-ifelse/template.templ b/templ/generator/test-ifelse/template.templ new file mode 100644 index 0000000..92ace50 --- /dev/null +++ b/templ/generator/test-ifelse/template.templ @@ -0,0 +1,9 @@ +package ifelse + +templ render(d data) { + if d.IsTrue() { + { "True" } + } else { + { "False" } + } +} diff --git a/templ/generator/test-ifelse/template_templ.go b/templ/generator/test-ifelse/template_templ.go new file mode 100644 index 0000000..3041386 --- /dev/null +++ b/templ/generator/test-ifelse/template_templ.go @@ -0,0 +1,57 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package ifelse + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(d data) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + if d.IsTrue() { + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("True") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-ifelse/template.templ`, Line: 5, Col: 10} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("False") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-ifelse/template.templ`, Line: 7, Col: 11} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-import/expected.html b/templ/generator/test-import/expected.html new file mode 100644 index 0000000..6f88dc9 --- /dev/null +++ b/templ/generator/test-import/expected.html @@ -0,0 +1,5 @@ +
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
\ No newline at end of file diff --git a/templ/generator/test-import/render_test.go b/templ/generator/test-import/render_test.go new file mode 100644 index 0000000..ff0f1c8 --- /dev/null +++ b/templ/generator/test-import/render_test.go @@ -0,0 +1,23 @@ +package testimport + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := main() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-import/template.templ b/templ/generator/test-import/template.templ new file mode 100644 index 0000000..88d50b1 --- /dev/null +++ b/templ/generator/test-import/template.templ @@ -0,0 +1,27 @@ +package testimport + +templ listItem() { +
  • + { children... } +
  • +} + +templ list() { +
      + { children... } +
    +} + +templ main() { + @list() { + @listItem() { + Item 1 + } + @listItem() { + Item 2 + } + @listItem() { + Item 3 + } + } +} diff --git a/templ/generator/test-import/template_templ.go b/templ/generator/test-import/template_templ.go new file mode 100644 index 0000000..6bcfa7d --- /dev/null +++ b/templ/generator/test-import/template_templ.go @@ -0,0 +1,202 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testimport + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func listItem() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func list() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
      ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func main() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "Item 1") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = listItem().Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "Item 2") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = listItem().Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var7 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "Item 3") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = listItem().Render(templ.WithChildren(ctx, templ_7745c5c3_Var7), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = list().Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-js-unsafe-usage/expected.html b/templ/generator/test-js-unsafe-usage/expected.html new file mode 100644 index 0000000..d41f233 --- /dev/null +++ b/templ/generator/test-js-unsafe-usage/expected.html @@ -0,0 +1,6 @@ + + diff --git a/templ/generator/test-js-unsafe-usage/render_test.go b/templ/generator/test-js-unsafe-usage/render_test.go new file mode 100644 index 0000000..ca8ec51 --- /dev/null +++ b/templ/generator/test-js-unsafe-usage/render_test.go @@ -0,0 +1,23 @@ +package testjsunsafeusage + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := TestComponent() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-js-unsafe-usage/template.templ b/templ/generator/test-js-unsafe-usage/template.templ new file mode 100644 index 0000000..3ec51b4 --- /dev/null +++ b/templ/generator/test-js-unsafe-usage/template.templ @@ -0,0 +1,6 @@ +package testjsunsafeusage + +templ TestComponent() { + + @templ.JSUnsafeFuncCall("// Arbitrary JS code") +} diff --git a/templ/generator/test-js-unsafe-usage/template_templ.go b/templ/generator/test-js-unsafe-usage/template_templ.go new file mode 100644 index 0000000..6eef1be --- /dev/null +++ b/templ/generator/test-js-unsafe-usage/template_templ.go @@ -0,0 +1,57 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testjsunsafeusage + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func TestComponent() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, templ.JSUnsafeFuncCall("anythingILike('blah')")) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSUnsafeFuncCall("// Arbitrary JS code").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-js-usage/expected.html b/templ/generator/test-js-usage/expected.html new file mode 100644 index 0000000..fd433e5 --- /dev/null +++ b/templ/generator/test-js-usage/expected.html @@ -0,0 +1,27 @@ + + + + + + + diff --git a/templ/generator/test-js-usage/render_test.go b/templ/generator/test-js-usage/render_test.go new file mode 100644 index 0000000..ed03f71 --- /dev/null +++ b/templ/generator/test-js-usage/render_test.go @@ -0,0 +1,23 @@ +package testjsusage + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := TestComponent() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-js-usage/template.templ b/templ/generator/test-js-usage/template.templ new file mode 100644 index 0000000..da2340d --- /dev/null +++ b/templ/generator/test-js-usage/template.templ @@ -0,0 +1,27 @@ +package testjsusage + +import "time" + +var onceHandle = templ.NewOnceHandle() + +templ TestComponent() { + + @onceHandle.Once() { + + } + + + @templ.JSFuncCall("customAlert", "Runs on page load", time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)) + + +} diff --git a/templ/generator/test-js-usage/template_templ.go b/templ/generator/test-js-usage/template_templ.go new file mode 100644 index 0000000..425aa4d --- /dev/null +++ b/templ/generator/test-js-usage/template_templ.go @@ -0,0 +1,138 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testjsusage + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "time" + +var onceHandle = templ.NewOnceHandle() + +func TestComponent() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, templ.JSFuncCall("alert", "Hello, World!")) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = onceHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, templ.JSFuncCall("customAlert", "Hello, custom alert 1: ", time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC))) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, templ.JSFuncCall("customAlert", "Hello, custom alert 2: ", time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC))) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.JSFuncCall("customAlert", "Runs on page load", time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, templ.JSFuncCall("onClickEventHandler", templ.JSExpression("event"), "1234")) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-method/expected.html b/templ/generator/test-method/expected.html new file mode 100644 index 0000000..7bdc726 --- /dev/null +++ b/templ/generator/test-method/expected.html @@ -0,0 +1 @@ +
    You can implement methods on a type.
    diff --git a/templ/generator/test-method/render_test.go b/templ/generator/test-method/render_test.go new file mode 100644 index 0000000..09951e8 --- /dev/null +++ b/templ/generator/test-method/render_test.go @@ -0,0 +1,26 @@ +package testmethod + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + d := Data{ + message: "You can implement methods on a type.", + } + component := d.Method() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-method/template.templ b/templ/generator/test-method/template.templ new file mode 100644 index 0000000..acd5ab9 --- /dev/null +++ b/templ/generator/test-method/template.templ @@ -0,0 +1,9 @@ +package testmethod + +type Data struct { + message string +} + +templ (d Data) Method() { +
    { d.message }
    +} diff --git a/templ/generator/test-method/template_templ.go b/templ/generator/test-method/template_templ.go new file mode 100644 index 0000000..76db46a --- /dev/null +++ b/templ/generator/test-method/template_templ.go @@ -0,0 +1,57 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testmethod + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +type Data struct { + message string +} + +func (d Data) Method() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(d.message) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-method/template.templ`, Line: 8, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-once/expected.html b/templ/generator/test-once/expected.html new file mode 100644 index 0000000..84eaf7d --- /dev/null +++ b/templ/generator/test-once/expected.html @@ -0,0 +1,7 @@ + + + diff --git a/templ/generator/test-once/render_test.go b/templ/generator/test-once/render_test.go new file mode 100644 index 0000000..3d1f237 --- /dev/null +++ b/templ/generator/test-once/render_test.go @@ -0,0 +1,23 @@ +package once + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-once/template.templ b/templ/generator/test-once/template.templ new file mode 100644 index 0000000..0486047 --- /dev/null +++ b/templ/generator/test-once/template.templ @@ -0,0 +1,19 @@ +package once + +var helloHandle = templ.NewOnceHandle() + +templ hello(label, name string) { + @helloHandle.Once() { + + } + +} + +templ render() { + @hello("Hello User", "user") + @hello("Hello World", "world") +} diff --git a/templ/generator/test-once/template_templ.go b/templ/generator/test-once/template_templ.go new file mode 100644 index 0000000..3de5dd1 --- /dev/null +++ b/templ/generator/test-once/template_templ.go @@ -0,0 +1,123 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package once + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +var helloHandle = templ.NewOnceHandle() + +func hello(label, name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = helloHandle.Once().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func render() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = hello("Hello User", "user").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = hello("Hello World", "world").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-only-scripts/expected.html b/templ/generator/test-only-scripts/expected.html new file mode 100644 index 0000000..5072ab8 --- /dev/null +++ b/templ/generator/test-only-scripts/expected.html @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/templ/generator/test-only-scripts/render_test.go b/templ/generator/test-only-scripts/render_test.go new file mode 100644 index 0000000..3b712b4 --- /dev/null +++ b/templ/generator/test-only-scripts/render_test.go @@ -0,0 +1,23 @@ +package onlyscripts + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + script := withParameters("hello", "world", 42069) + + diff, err := htmldiff.Diff(script, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-only-scripts/template.templ b/templ/generator/test-only-scripts/template.templ new file mode 100644 index 0000000..750c37e --- /dev/null +++ b/templ/generator/test-only-scripts/template.templ @@ -0,0 +1,5 @@ +package onlyscripts + +script withParameters(a string, b string, c int) { + console.log(a, b, c); +} diff --git a/templ/generator/test-only-scripts/template_templ.go b/templ/generator/test-only-scripts/template_templ.go new file mode 100644 index 0000000..dda534c --- /dev/null +++ b/templ/generator/test-only-scripts/template_templ.go @@ -0,0 +1,21 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package onlyscripts + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func withParameters(a string, b string, c int) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withParameters_1056`, + Function: `function __templ_withParameters_1056(a, b, c){console.log(a, b, c); +}`, + Call: templ.SafeScript(`__templ_withParameters_1056`, a, b, c), + CallInline: templ.SafeScriptInline(`__templ_withParameters_1056`, a, b, c), + } +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-raw-elements/expected.html b/templ/generator/test-raw-elements/expected.html new file mode 100644 index 0000000..5b41f2a --- /dev/null +++ b/templ/generator/test-raw-elements/expected.html @@ -0,0 +1,19 @@ + + + + + + +

    Hello

    +
    World
    + + diff --git a/templ/generator/test-raw-elements/render_test.go b/templ/generator/test-raw-elements/render_test.go new file mode 100644 index 0000000..bbb5ecb --- /dev/null +++ b/templ/generator/test-raw-elements/render_test.go @@ -0,0 +1,22 @@ +package testrawelements + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := Example() + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-raw-elements/template.templ b/templ/generator/test-raw-elements/template.templ new file mode 100644 index 0000000..9073f2c --- /dev/null +++ b/templ/generator/test-raw-elements/template.templ @@ -0,0 +1,23 @@ +package testrawelements + +templ Example() { + + + + + + +

    Hello

    + @templ.Raw("
    World
    ") + + +} diff --git a/templ/generator/test-raw-elements/template_templ.go b/templ/generator/test-raw-elements/template_templ.go new file mode 100644 index 0000000..042a20c --- /dev/null +++ b/templ/generator/test-raw-elements/template_templ.go @@ -0,0 +1,48 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testrawelements + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Example() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

    Hello

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.Raw("
    World
    ").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-script-inline/expected.html b/templ/generator/test-script-inline/expected.html new file mode 100644 index 0000000..8892088 --- /dev/null +++ b/templ/generator/test-script-inline/expected.html @@ -0,0 +1,20 @@ + + + + + + diff --git a/templ/generator/test-script-inline/render_test.go b/templ/generator/test-script-inline/render_test.go new file mode 100644 index 0000000..0507e44 --- /dev/null +++ b/templ/generator/test-script-inline/render_test.go @@ -0,0 +1,23 @@ +package testscriptinline + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := InlineJavascript("injected") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-script-inline/template.templ b/templ/generator/test-script-inline/template.templ new file mode 100644 index 0000000..f85b357 --- /dev/null +++ b/templ/generator/test-script-inline/template.templ @@ -0,0 +1,17 @@ +package testscriptinline + +script withParameters(a string, b string, c int) { + console.log(a, b, c); +} + +script withoutParameters() { + alert("hello"); +} + +templ InlineJavascript(a string) { + @withoutParameters() + @withParameters(a, "test", 123) + // Call once more, to ensure it's defined only once + @withoutParameters() + @withParameters(a, "test", 123) +} diff --git a/templ/generator/test-script-inline/template_templ.go b/templ/generator/test-script-inline/template_templ.go new file mode 100644 index 0000000..73708fd --- /dev/null +++ b/templ/generator/test-script-inline/template_templ.go @@ -0,0 +1,72 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testscriptinline + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func withParameters(a string, b string, c int) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withParameters_1056`, + Function: `function __templ_withParameters_1056(a, b, c){console.log(a, b, c); +}`, + Call: templ.SafeScript(`__templ_withParameters_1056`, a, b, c), + CallInline: templ.SafeScriptInline(`__templ_withParameters_1056`, a, b, c), + } +} + +func withoutParameters() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withoutParameters_6bbf`, + Function: `function __templ_withoutParameters_6bbf(){alert("hello"); +}`, + Call: templ.SafeScript(`__templ_withoutParameters_6bbf`), + CallInline: templ.SafeScriptInline(`__templ_withoutParameters_6bbf`), + } +} + +func InlineJavascript(a string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = withoutParameters().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = withParameters(a, "test", 123).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = withoutParameters().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = withParameters(a, "test", 123).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-script-usage-nonce/expected.html b/templ/generator/test-script-usage-nonce/expected.html new file mode 100644 index 0000000..b896518 --- /dev/null +++ b/templ/generator/test-script-usage-nonce/expected.html @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/templ/generator/test-script-usage-nonce/render_test.go b/templ/generator/test-script-usage-nonce/render_test.go new file mode 100644 index 0000000..b39cbba --- /dev/null +++ b/templ/generator/test-script-usage-nonce/render_test.go @@ -0,0 +1,26 @@ +package testscriptusage + +import ( + "context" + _ "embed" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := ThreeButtons() + + ctx := templ.WithNonce(context.Background(), "nonce1") + _, diff, err := htmldiff.DiffCtx(ctx, component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-script-usage-nonce/template.templ b/templ/generator/test-script-usage-nonce/template.templ new file mode 100644 index 0000000..9364a75 --- /dev/null +++ b/templ/generator/test-script-usage-nonce/template.templ @@ -0,0 +1,44 @@ +package testscriptusage + +script withParameters(a string, b string, c int) { + console.log(a, b, c); +} + +script withoutParameters() { + alert("hello"); +} + +script onClick() { + alert("clicked"); +} + +templ Button(text string) { + +} + +script withComment() { + //' +} + +templ ThreeButtons() { + @Button("A") + @Button("B") + + + + @Conditional(true) +} + +script conditionalScript() { + alert("conditional"); +} + +templ Conditional(show bool) { + +} diff --git a/templ/generator/test-script-usage-nonce/template_templ.go b/templ/generator/test-script-usage-nonce/template_templ.go new file mode 100644 index 0000000..eff0b1c --- /dev/null +++ b/templ/generator/test-script-usage-nonce/template_templ.go @@ -0,0 +1,235 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testscriptusage + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func withParameters(a string, b string, c int) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withParameters_1056`, + Function: `function __templ_withParameters_1056(a, b, c){console.log(a, b, c); +}`, + Call: templ.SafeScript(`__templ_withParameters_1056`, a, b, c), + CallInline: templ.SafeScriptInline(`__templ_withParameters_1056`, a, b, c), + } +} + +func withoutParameters() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withoutParameters_6bbf`, + Function: `function __templ_withoutParameters_6bbf(){alert("hello"); +}`, + Call: templ.SafeScript(`__templ_withoutParameters_6bbf`), + CallInline: templ.SafeScriptInline(`__templ_withoutParameters_6bbf`), + } +} + +func onClick() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_onClick_657d`, + Function: `function __templ_onClick_657d(){alert("clicked"); +}`, + Call: templ.SafeScript(`__templ_onClick_657d`), + CallInline: templ.SafeScriptInline(`__templ_onClick_657d`), + } +} + +func Button(text string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, withParameters("test", text, 123), withoutParameters()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func withComment() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withComment_9cf8`, + Function: `function __templ_withComment_9cf8(){//' +}`, + Call: templ.SafeScript(`__templ_withComment_9cf8`), + CallInline: templ.SafeScriptInline(`__templ_withComment_9cf8`), + } +} + +func ThreeButtons() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Button("A").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = Button("B").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, onClick()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = Conditional(true).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func conditionalScript() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_conditionalScript_de41`, + Function: `function __templ_conditionalScript_de41(){alert("conditional"); +}`, + Call: templ.SafeScript(`__templ_conditionalScript_de41`), + CallInline: templ.SafeScriptInline(`__templ_conditionalScript_de41`), + } +} + +func Conditional(show bool) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, conditionalScript()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-script-usage/expected.html b/templ/generator/test-script-usage/expected.html new file mode 100644 index 0000000..b0dec32 --- /dev/null +++ b/templ/generator/test-script-usage/expected.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/templ/generator/test-script-usage/render_test.go b/templ/generator/test-script-usage/render_test.go new file mode 100644 index 0000000..9aea4ba --- /dev/null +++ b/templ/generator/test-script-usage/render_test.go @@ -0,0 +1,23 @@ +package testscriptusage + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := ThreeButtons() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-script-usage/template.templ b/templ/generator/test-script-usage/template.templ new file mode 100644 index 0000000..60d6b9c --- /dev/null +++ b/templ/generator/test-script-usage/template.templ @@ -0,0 +1,58 @@ +package testscriptusage + +script withParameters(a string, b string, c int) { + console.log(a, b, c); +} + +script withoutParameters() { + alert("hello"); +} + +script onClick() { + alert("clicked"); +} + +templ Button(text string) { + +} + +script withComment() { + //' +} + +script whenButtonIsClicked(event templ.JSExpression) { + console.log(event.target) +} + +templ ThreeButtons() { + @Button("A") + @Button("B") + + + + + @Conditional(true) + @ScriptOnLoad() +} + +script conditionalScript() { + alert("conditional"); +} + +templ Conditional(show bool) { + +} + +script alertTest() { + alert('testing'); +} + +templ ScriptOnLoad() { + +} diff --git a/templ/generator/test-script-usage/template_templ.go b/templ/generator/test-script-usage/template_templ.go new file mode 100644 index 0000000..56f0686 --- /dev/null +++ b/templ/generator/test-script-usage/template_templ.go @@ -0,0 +1,318 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testscriptusage + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func withParameters(a string, b string, c int) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withParameters_1056`, + Function: `function __templ_withParameters_1056(a, b, c){console.log(a, b, c); +}`, + Call: templ.SafeScript(`__templ_withParameters_1056`, a, b, c), + CallInline: templ.SafeScriptInline(`__templ_withParameters_1056`, a, b, c), + } +} + +func withoutParameters() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withoutParameters_6bbf`, + Function: `function __templ_withoutParameters_6bbf(){alert("hello"); +}`, + Call: templ.SafeScript(`__templ_withoutParameters_6bbf`), + CallInline: templ.SafeScriptInline(`__templ_withoutParameters_6bbf`), + } +} + +func onClick() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_onClick_657d`, + Function: `function __templ_onClick_657d(){alert("clicked"); +}`, + Call: templ.SafeScript(`__templ_onClick_657d`), + CallInline: templ.SafeScriptInline(`__templ_onClick_657d`), + } +} + +func Button(text string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, withParameters("test", text, 123), withoutParameters()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func withComment() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_withComment_9cf8`, + Function: `function __templ_withComment_9cf8(){//' +}`, + Call: templ.SafeScript(`__templ_withComment_9cf8`), + CallInline: templ.SafeScriptInline(`__templ_withComment_9cf8`), + } +} + +func whenButtonIsClicked(event templ.JSExpression) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_whenButtonIsClicked_253e`, + Function: `function __templ_whenButtonIsClicked_253e(event){console.log(event.target) +}`, + Call: templ.SafeScript(`__templ_whenButtonIsClicked_253e`, event), + CallInline: templ.SafeScriptInline(`__templ_whenButtonIsClicked_253e`, event), + } +} + +func ThreeButtons() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = Button("A").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = Button("B").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, onClick()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, whenButtonIsClicked(templ.JSExpression("event"))) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = Conditional(true).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = ScriptOnLoad().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func conditionalScript() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_conditionalScript_de41`, + Function: `function __templ_conditionalScript_de41(){alert("conditional"); +}`, + Call: templ.SafeScript(`__templ_conditionalScript_de41`), + CallInline: templ.SafeScriptInline(`__templ_conditionalScript_de41`), + } +} + +func Conditional(show bool) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, conditionalScript()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func alertTest() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_alertTest_eadf`, + Function: `function __templ_alertTest_eadf(){alert('testing'); +}`, + Call: templ.SafeScript(`__templ_alertTest_eadf`), + CallInline: templ.SafeScriptInline(`__templ_alertTest_eadf`), + } +} + +func ScriptOnLoad() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, alertTest()) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-spread-attributes/expected.html b/templ/generator/test-spread-attributes/expected.html new file mode 100644 index 0000000..6c34ff3 --- /dev/null +++ b/templ/generator/test-spread-attributes/expected.html @@ -0,0 +1,11 @@ +
    + + text + +
    + text2 +
    +
    + text3 +
    +
    diff --git a/templ/generator/test-spread-attributes/render_test.go b/templ/generator/test-spread-attributes/render_test.go new file mode 100644 index 0000000..2594c86 --- /dev/null +++ b/templ/generator/test-spread-attributes/render_test.go @@ -0,0 +1,65 @@ +package testspreadattributes + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := BasicTemplate(templ.Attributes{ + // Should render as `bool` as the value is true, and the conditional render is also true. + "bool": templ.KV(true, true), + // Should not render, as the conditional render value is false. + "bool-disabled": templ.KV(true, false), + // Should render non-nil string values. + "data-attr": ptr("value"), + // Should render non-nil boolean values that evaluate to true. + "data-attr-bool": ptr(true), + // Should render as `dateId="my-custom-id"`. + "dateId": "my-custom-id", + // Should render as `hx-get="/page"`. + "hx-get": "/page", + // Should render as `id="test"`. + "id": "test", + // Should not render a nil string pointer. + "key": nilPtr[string](), + // Should not render a nil boolean value. + "boolkey": nilPtr[bool](), + // Should not render, as the attribute value, and the conditional render value is false. + "no-bool": templ.KV(false, false), + // Should not render, as the conditional render value is false. + "no-text": templ.KV("empty", false), + // Should render as `nonshare`, as the value is true. + "nonshade": true, + // Should not render, as the value is false. + "shade": false, + // Should render text="lorem" as the value is true. + "text": templ.KV("lorem", true), + // Optional attribute based on result of func() bool. + "optional-from-func-false": func() bool { return false }, + // Optional attribute based on result of func() bool. + "optional-from-func-true": func() bool { return true }, + }) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} + +func nilPtr[T any]() *T { + return nil +} + +func ptr[T any](x T) *T { + return &x +} diff --git a/templ/generator/test-spread-attributes/template.templ b/templ/generator/test-spread-attributes/template.templ new file mode 100644 index 0000000..282783e --- /dev/null +++ b/templ/generator/test-spread-attributes/template.templ @@ -0,0 +1,17 @@ +package testspreadattributes + +templ BasicTemplate(spread templ.Attributes) { +
    + text +
    text2
    +
    text3
    +
    +} diff --git a/templ/generator/test-spread-attributes/template_templ.go b/templ/generator/test-spread-attributes/template_templ.go new file mode 100644 index 0000000..68f884d --- /dev/null +++ b/templ/generator/test-spread-attributes/template_templ.go @@ -0,0 +1,68 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testspreadattributes + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func BasicTemplate(spread templ.Attributes) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    texttext2
    text3
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-string-errors/expected.html b/templ/generator/test-string-errors/expected.html new file mode 100644 index 0000000..893ecdf --- /dev/null +++ b/templ/generator/test-string-errors/expected.html @@ -0,0 +1,5 @@ +
      +
    • raw
    • +
    • OK
    • +
    • OK2
    • +
    diff --git a/templ/generator/test-string-errors/render_test.go b/templ/generator/test-string-errors/render_test.go new file mode 100644 index 0000000..d279881 --- /dev/null +++ b/templ/generator/test-string-errors/render_test.go @@ -0,0 +1,57 @@ +package teststringerrs + +import ( + "bytes" + "context" + _ "embed" + "errors" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + t.Run("can render without error", func(t *testing.T) { + component := TestComponent(nil) + + _, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + t.Run("string expressions can return errors", func(t *testing.T) { + errSomethingBad := errors.New("bad error") + + err := TestComponent(errSomethingBad).Render(context.Background(), &bytes.Buffer{}) + if err == nil { + t.Fatalf("expected error, but got nil") + } + + t.Run("the errors are templ errors", func(t *testing.T) { + var templateErr templ.Error + if !errors.As(err, &templateErr) { + t.Fatalf("expected error to be templ.Error, but got %T", err) + } + if templateErr.FileName != `generator/test-string-errors/template.templ` { + t.Errorf("expected error in `generator/test-string-errors/template.templ`, but got %v", templateErr.FileName) + } + if templateErr.Line != 18 { + t.Errorf("expected error on line 18, but got %v", templateErr.Line) + } + if templateErr.Col != 26 { + t.Errorf("expected error on column 26, but got %v", templateErr.Col) + } + }) + + t.Run("the underlying error can be unwrapped", func(t *testing.T) { + if !errors.Is(err, errSomethingBad) { + t.Errorf("expected error: %v, but got %v", errSomethingBad, err) + } + }) + + }) +} diff --git a/templ/generator/test-string-errors/template.templ b/templ/generator/test-string-errors/template.templ new file mode 100644 index 0000000..daf9bed --- /dev/null +++ b/templ/generator/test-string-errors/template.templ @@ -0,0 +1,20 @@ +package teststringerrs + +func funcWithNoError() (s string) { + return "OK" +} + +func funcWithError(in error) (s string, err error) { + if in != nil { + return "", in + } + return "OK2", nil +} + +templ TestComponent(err error) { +
      +
    • { "raw" }
    • +
    • { funcWithNoError() }
    • +
    • { funcWithError(err) }
    • +
    +} diff --git a/templ/generator/test-string-errors/template_templ.go b/templ/generator/test-string-errors/template_templ.go new file mode 100644 index 0000000..8d7b234 --- /dev/null +++ b/templ/generator/test-string-errors/template_templ.go @@ -0,0 +1,90 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package teststringerrs + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func funcWithNoError() (s string) { + return "OK" +} + +func funcWithError(in error) (s string, err error) { + if in != nil { + return "", in + } + return "OK2", nil +} + +func TestComponent(err error) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("raw") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string-errors/template.templ`, Line: 16, Col: 13} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
    • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(funcWithNoError()) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string-errors/template.templ`, Line: 17, Col: 25} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
    • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(funcWithError(err)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string-errors/template.templ`, Line: 18, Col: 26} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-string/expected.html b/templ/generator/test-string/expected.html new file mode 100644 index 0000000..55e0258 --- /dev/null +++ b/templ/generator/test-string/expected.html @@ -0,0 +1,5 @@ +
      +
    • +
    • Strings are HTML escaped. So ampersands (&), greater than (>), and less than symbols (<) are converted.
    • +
    • Spaces are preserved.
    • +
    diff --git a/templ/generator/test-string/render_test.go b/templ/generator/test-string/render_test.go new file mode 100644 index 0000000..7774362 --- /dev/null +++ b/templ/generator/test-string/render_test.go @@ -0,0 +1,23 @@ +package teststring + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render(`Strings are HTML escaped. So ampersands (&), greater than (>), and less than symbols (<) are converted.`) + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-string/template.templ b/templ/generator/test-string/template.templ new file mode 100644 index 0000000..f2976da --- /dev/null +++ b/templ/generator/test-string/template.templ @@ -0,0 +1,9 @@ +package teststring + +templ render(s string) { +
      +
    • { }
    • +
    • { s }
    • +
    • { "Spaces" } { "are" } { "preserved." }
    • +
    +} diff --git a/templ/generator/test-string/template_templ.go b/templ/generator/test-string/template_templ.go new file mode 100644 index 0000000..e295b4a --- /dev/null +++ b/templ/generator/test-string/template_templ.go @@ -0,0 +1,92 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package teststring + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(s string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(s) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string/template.templ`, Line: 6, Col: 9} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
    • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("Spaces") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string/template.templ`, Line: 7, Col: 16} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 string + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("are") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string/template.templ`, Line: 7, Col: 26} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("preserved.") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-string/template.templ`, Line: 7, Col: 43} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-style-attribute/expected.html b/templ/generator/test-style-attribute/expected.html new file mode 100644 index 0000000..479949a --- /dev/null +++ b/templ/generator/test-style-attribute/expected.html @@ -0,0 +1,2 @@ + + diff --git a/templ/generator/test-style-attribute/render_test.go b/templ/generator/test-style-attribute/render_test.go new file mode 100644 index 0000000..3f5a741 --- /dev/null +++ b/templ/generator/test-style-attribute/render_test.go @@ -0,0 +1,64 @@ +package teststyleattribute + +import ( + _ "embed" + "fmt" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + var stringCSS = "background-color:blue;color:red" + var safeCSS = templ.SafeCSS("background-color:blue;color:red;") + var mapStringString = map[string]string{ + "color": "red", + "background-color": "blue", + } + var mapStringSafeCSSProperty = map[string]templ.SafeCSSProperty{ + "color": templ.SafeCSSProperty("red"), + "background-color": templ.SafeCSSProperty("blue"), + } + var kvStringStringSlice = []templ.KeyValue[string, string]{ + templ.KV("background-color", "blue"), + templ.KV("color", "red"), + } + var kvStringBoolSlice = []templ.KeyValue[string, bool]{ + templ.KV("background-color:blue", true), + templ.KV("color:red", true), + templ.KV("color:blue", false), + } + var kvSafeCSSBoolSlice = []templ.KeyValue[templ.SafeCSS, bool]{ + templ.KV(templ.SafeCSS("background-color:blue"), true), + templ.KV(templ.SafeCSS("color:red"), true), + templ.KV(templ.SafeCSS("color:blue"), false), + } + + tests := []any{ + stringCSS, + safeCSS, + mapStringString, + mapStringSafeCSSProperty, + kvStringStringSlice, + kvStringBoolSlice, + kvSafeCSSBoolSlice, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("%T", test), func(t *testing.T) { + component := Button(test, "Click me") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/generator/test-style-attribute/template.templ b/templ/generator/test-style-attribute/template.templ new file mode 100644 index 0000000..3fcd0ae --- /dev/null +++ b/templ/generator/test-style-attribute/template.templ @@ -0,0 +1,10 @@ +package teststyleattribute + +templ Button[T any](style T, text string) { + + +} + +func getFunctionResult() (string, error) { + return "background-color: red", nil +} diff --git a/templ/generator/test-style-attribute/template_templ.go b/templ/generator/test-style-attribute/template_templ.go new file mode 100644 index 0000000..649ce22 --- /dev/null +++ b/templ/generator/test-style-attribute/template_templ.go @@ -0,0 +1,96 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package teststyleattribute + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func Button[T any](style T, text string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func getFunctionResult() (string, error) { + return "background-color: red", nil +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-switch/render_test.go b/templ/generator/test-switch/render_test.go new file mode 100644 index 0000000..2c447c1 --- /dev/null +++ b/templ/generator/test-switch/render_test.go @@ -0,0 +1,24 @@ +package testswitch + +import ( + "context" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +var input = "a" + +const expected = `it was 'a'` + +func TestRender(t *testing.T) { + w := new(strings.Builder) + err := render(input).Render(context.Background(), w) + if err != nil { + t.Errorf("failed to render: %v", err) + } + if diff := cmp.Diff(expected, w.String()); diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-switch/template.templ b/templ/generator/test-switch/template.templ new file mode 100644 index 0000000..48ec62e --- /dev/null +++ b/templ/generator/test-switch/template.templ @@ -0,0 +1,10 @@ +package testswitch + +templ render(input string) { + switch input { + case "a": + { "it was 'a'" } + default: + { "it was something else" } + } +} diff --git a/templ/generator/test-switch/template_templ.go b/templ/generator/test-switch/template_templ.go new file mode 100644 index 0000000..38831f6 --- /dev/null +++ b/templ/generator/test-switch/template_templ.go @@ -0,0 +1,58 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testswitch + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render(input string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch input { + case "a": + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("it was 'a'") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-switch/template.templ`, Line: 6, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("it was something else") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-switch/template.templ`, Line: 8, Col: 28} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-switchdefault/render_test.go b/templ/generator/test-switchdefault/render_test.go new file mode 100644 index 0000000..f8a5a25 --- /dev/null +++ b/templ/generator/test-switchdefault/render_test.go @@ -0,0 +1,24 @@ +package testswitchdefault + +import ( + "context" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +var input = "b" + +const expected = `it was something else` + +func TestRender(t *testing.T) { + w := new(strings.Builder) + err := template(input).Render(context.Background(), w) + if err != nil { + t.Errorf("failed to render: %v", err) + } + if diff := cmp.Diff(expected, w.String()); diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-switchdefault/template.templ b/templ/generator/test-switchdefault/template.templ new file mode 100644 index 0000000..7812f52 --- /dev/null +++ b/templ/generator/test-switchdefault/template.templ @@ -0,0 +1,10 @@ +package testswitchdefault + +templ template(input string) { + switch input { + case "a": + { "it was 'a'" } + default: + { "it was something else" } + } +} diff --git a/templ/generator/test-switchdefault/template_templ.go b/templ/generator/test-switchdefault/template_templ.go new file mode 100644 index 0000000..9e3a877 --- /dev/null +++ b/templ/generator/test-switchdefault/template_templ.go @@ -0,0 +1,58 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testswitchdefault + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func template(input string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch input { + case "a": + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs("it was 'a'") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-switchdefault/template.templ`, Line: 6, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs("it was something else") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-switchdefault/template.templ`, Line: 8, Col: 28} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-templ-element/expected.html b/templ/generator/test-templ-element/expected.html new file mode 100644 index 0000000..e662601 --- /dev/null +++ b/templ/generator/test-templ-element/expected.html @@ -0,0 +1 @@ +
    child1
    child2
    child3
    diff --git a/templ/generator/test-templ-element/render_test.go b/templ/generator/test-templ-element/render_test.go new file mode 100644 index 0000000..a3c1109 --- /dev/null +++ b/templ/generator/test-templ-element/render_test.go @@ -0,0 +1,24 @@ +package testtemplelement + +import ( + "testing" + + _ "embed" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := template() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-templ-element/template.templ b/templ/generator/test-templ-element/template.templ new file mode 100644 index 0000000..ff015c3 --- /dev/null +++ b/templ/generator/test-templ-element/template.templ @@ -0,0 +1,22 @@ +package testtemplelement + +import "fmt" + +templ wrapper(index int) { +
    + { children... } +
    +} + +templ template() { + @wrapper(1) { + child1 + @wrapper(2) { + child2 + @wrapper(3) { + child3 + @wrapper(4) + } + } + } +} diff --git a/templ/generator/test-templ-element/template_templ.go b/templ/generator/test-templ-element/template_templ.go new file mode 100644 index 0000000..305b563 --- /dev/null +++ b/templ/generator/test-templ-element/template_templ.go @@ -0,0 +1,158 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testtemplelement + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func wrapper(index int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func template() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "child1") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "child2") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Var6 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "child3") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = wrapper(4).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = wrapper(3).Render(templ.WithChildren(ctx, templ_7745c5c3_Var6), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = wrapper(2).Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) + templ_7745c5c3_Err = wrapper(1).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-templ-in-go-template/expected.html b/templ/generator/test-templ-in-go-template/expected.html new file mode 100644 index 0000000..cf99512 --- /dev/null +++ b/templ/generator/test-templ-in-go-template/expected.html @@ -0,0 +1,6 @@ + + + +
    Hello, World!
    + + diff --git a/templ/generator/test-templ-in-go-template/render_test.go b/templ/generator/test-templ-in-go-template/render_test.go new file mode 100644 index 0000000..9fa7337 --- /dev/null +++ b/templ/generator/test-templ-in-go-template/render_test.go @@ -0,0 +1,39 @@ +package testgotemplates + +import ( + "context" + _ "embed" + "strings" + "testing" + + "github.com/a-h/templ" + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func TestExample(t *testing.T) { + // Create the templ component. + templComponent := greeting() + html, err := templ.ToGoHTML(context.Background(), templComponent) + if err != nil { + t.Fatalf("failed to convert to html: %v", err) + } + + // Use it within the text/html template. + b := new(strings.Builder) + err = example.Execute(b, html) + if err != nil { + t.Fatalf("failed to execute template: %v", err) + } + + // Compare the output with the expected. + diff, err := htmldiff.DiffStrings(expected, b.String()) + if err != nil { + t.Fatalf("failed to diff strings: %v", err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-templ-in-go-template/template.templ b/templ/generator/test-templ-in-go-template/template.templ new file mode 100644 index 0000000..86378d1 --- /dev/null +++ b/templ/generator/test-templ-in-go-template/template.templ @@ -0,0 +1,15 @@ +package testgotemplates + +import "html/template" + +var example = template.Must(template.New("example").Parse(` + + + {{ . }} + + +`)) + +templ greeting() { +
    Hello, World!
    +} diff --git a/templ/generator/test-templ-in-go-template/template_templ.go b/templ/generator/test-templ-in-go-template/template_templ.go new file mode 100644 index 0000000..f38a8c0 --- /dev/null +++ b/templ/generator/test-templ-in-go-template/template_templ.go @@ -0,0 +1,50 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testgotemplates + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "html/template" + +var example = template.Must(template.New("example").Parse(` + + + {{ . }} + + +`)) + +func greeting() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    Hello, World!
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-text-whitespace/render_test.go b/templ/generator/test-text-whitespace/render_test.go new file mode 100644 index 0000000..ebf429a --- /dev/null +++ b/templ/generator/test-text-whitespace/render_test.go @@ -0,0 +1,53 @@ +package testtextwhitespace + +import ( + "context" + "strings" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestTextWhitespace(t *testing.T) { + for _, test := range []struct { + name string + input templ.Component + expected string + }{ + { + name: "whitespace is added within templ statements", + input: WhitespaceIsAddedWithinTemplStatements(), + expected: WhitespaceIsAddedWithinTemplStatementsExpected, + }, + { + name: "inline elements are not padded", + input: InlineElementsAreNotPadded(), + expected: InlineElementsAreNotPaddedExpected, + }, + { + name: "whitespace in HTML is normalised", + input: WhiteSpaceInHTMLIsNormalised(), + expected: WhiteSpaceInHTMLIsNormalisedExpected, + }, + { + name: "whitespace around values is maintained", + input: WhiteSpaceAroundValues(), + expected: WhiteSpaceAroundValuesExpected, + }, + { + name: "whitespace around templated values is maintained", + input: WhiteSpaceAroundTemplatedValues("templ", "allows whitespace around templated values."), + expected: WhiteSpaceAroundTemplatedValuesExpected, + }, + } { + w := new(strings.Builder) + err := test.input.Render(context.Background(), w) + if err != nil { + t.Errorf("failed to render: %v", err) + } + if diff := cmp.Diff(test.expected, w.String()); diff != "" { + t.Error(diff) + } + } +} diff --git a/templ/generator/test-text-whitespace/template.templ b/templ/generator/test-text-whitespace/template.templ new file mode 100644 index 0000000..55202e5 --- /dev/null +++ b/templ/generator/test-text-whitespace/template.templ @@ -0,0 +1,40 @@ +package testtextwhitespace + +templ WhitespaceIsAddedWithinTemplStatements() { +

    + This is some text. + if true { + So is this. + } +

    +} + +const WhitespaceIsAddedWithinTemplStatementsExpected = `

    This is some text. So is this.

    ` + +templ InlineElementsAreNotPadded() { +

    Inline text is spaced properly without adding extra spaces.

    +} + +const InlineElementsAreNotPaddedExpected = `

    Inline text is spaced properly without adding extra spaces.

    ` + +templ WhiteSpaceInHTMLIsNormalised() { +

    + newlines and other whitespace are stripped + but it is normalised + like HTML. +

    +} + +const WhiteSpaceInHTMLIsNormalisedExpected = `

    newlines and other whitespace are stripped but it is normalised like HTML.

    ` + +templ WhiteSpaceAroundValues() { +

    templ allows { "strings" } to be included in sentences.

    +} + +const WhiteSpaceAroundValuesExpected = `

    templ allows strings to be included in sentences.

    ` + +const WhiteSpaceAroundTemplatedValuesExpected = `
    templ allows whitespace around templated values.
    ` + +templ WhiteSpaceAroundTemplatedValues(prefix, statement string) { +
    { prefix } { statement }
    +} diff --git a/templ/generator/test-text-whitespace/template_templ.go b/templ/generator/test-text-whitespace/template_templ.go new file mode 100644 index 0000000..eb8a6b4 --- /dev/null +++ b/templ/generator/test-text-whitespace/template_templ.go @@ -0,0 +1,215 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testtextwhitespace + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func WhitespaceIsAddedWithinTemplStatements() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "

    This is some text. ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if true { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "So is this.") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsAddedWithinTemplStatementsExpected = `

    This is some text. So is this.

    ` + +func InlineElementsAreNotPadded() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

    Inline text is spaced properly without adding extra spaces.

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const InlineElementsAreNotPaddedExpected = `

    Inline text is spaced properly without adding extra spaces.

    ` + +func WhiteSpaceInHTMLIsNormalised() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

    newlines and other whitespace are stripped but it is normalised like HTML.

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhiteSpaceInHTMLIsNormalisedExpected = `

    newlines and other whitespace are stripped but it is normalised like HTML.

    ` + +func WhiteSpaceAroundValues() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

    templ allows ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs("strings") + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-text-whitespace/template.templ`, Line: 31, Col: 28} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " to be included in sentences.

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhiteSpaceAroundValuesExpected = `

    templ allows strings to be included in sentences.

    ` + +const WhiteSpaceAroundTemplatedValuesExpected = `
    templ allows whitespace around templated values.
    ` + +func WhiteSpaceAroundTemplatedValues(prefix, statement string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(prefix) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-text-whitespace/template.templ`, Line: 39, Col: 14} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(statement) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-text-whitespace/template.templ`, Line: 39, Col: 28} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-text/expected.html b/templ/generator/test-text/expected.html new file mode 100644 index 0000000..3c88a17 --- /dev/null +++ b/templ/generator/test-text/expected.html @@ -0,0 +1,4 @@ +
    Name: Luiz Bonfa
    +
    Text `with backticks`
    +
    Text `with backtick
    +
    Text `with backtick alongside variable: Luiz Bonfa
    diff --git a/templ/generator/test-text/render_test.go b/templ/generator/test-text/render_test.go new file mode 100644 index 0000000..f2eb457 --- /dev/null +++ b/templ/generator/test-text/render_test.go @@ -0,0 +1,24 @@ +package testtext + +import ( + "testing" + + _ "embed" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := BasicTemplate("Luiz Bonfa") + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-text/template.templ b/templ/generator/test-text/template.templ new file mode 100644 index 0000000..485ebd5 --- /dev/null +++ b/templ/generator/test-text/template.templ @@ -0,0 +1,8 @@ +package testtext + +templ BasicTemplate(name string) { +
    Name: { name }
    +
    Text `with backticks`
    +
    Text `with backtick
    +
    Text `with backtick alongside variable: { name }
    +} diff --git a/templ/generator/test-text/template_templ.go b/templ/generator/test-text/template_templ.go new file mode 100644 index 0000000..914f2c2 --- /dev/null +++ b/templ/generator/test-text/template_templ.go @@ -0,0 +1,66 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testtext + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func BasicTemplate(name string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
    Name: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var2 string + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-text/template.templ`, Line: 4, Col: 18} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "
    Text `with backticks`
    Text `with backtick
    Text `with backtick alongside variable: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 string + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/generator/test-text/template.templ`, Line: 7, Col: 52} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-void/expected.html b/templ/generator/test-void/expected.html new file mode 100644 index 0000000..909b967 --- /dev/null +++ b/templ/generator/test-void/expected.html @@ -0,0 +1,4 @@ +
    + +
    +
    diff --git a/templ/generator/test-void/render_test.go b/templ/generator/test-void/render_test.go new file mode 100644 index 0000000..e91f5db --- /dev/null +++ b/templ/generator/test-void/render_test.go @@ -0,0 +1,23 @@ +package testvoid + +import ( + _ "embed" + "testing" + + "github.com/a-h/templ/generator/htmldiff" +) + +//go:embed expected.html +var expected string + +func Test(t *testing.T) { + component := render() + + diff, err := htmldiff.Diff(component, expected) + if err != nil { + t.Fatal(err) + } + if diff != "" { + t.Error(diff) + } +} diff --git a/templ/generator/test-void/template.templ b/templ/generator/test-void/template.templ new file mode 100644 index 0000000..2ade2ff --- /dev/null +++ b/templ/generator/test-void/template.templ @@ -0,0 +1,8 @@ +package testvoid + +templ render() { +
    + +
    +
    +} diff --git a/templ/generator/test-void/template_templ.go b/templ/generator/test-void/template_templ.go new file mode 100644 index 0000000..331e5fd --- /dev/null +++ b/templ/generator/test-void/template_templ.go @@ -0,0 +1,40 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testvoid + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +func render() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "


    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/templ/generator/test-whitespace-around-go-keywords/render_test.go b/templ/generator/test-whitespace-around-go-keywords/render_test.go new file mode 100644 index 0000000..abc122d --- /dev/null +++ b/templ/generator/test-whitespace-around-go-keywords/render_test.go @@ -0,0 +1,78 @@ +package testwhitespacearoundgokeywords + +import ( + "context" + "strings" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestTextWhitespace(t *testing.T) { + for _, test := range []struct { + name string + input templ.Component + expected string + }{ + { + name: "whitespace is consistent in a true evaluated if statement", + input: WhitespaceIsConsistentInIf(true, false), + expected: WhitespaceIsConsistentInTrueIfExpected, + }, + { + name: "whitespace is consistent in a true evaluated else if statement", + input: WhitespaceIsConsistentInIf(false, true), + expected: WhitespaceIsConsistentInTrueElseIfExpected, + }, + { + name: "whitespace is consistent in a true evaluated else statement", + input: WhitespaceIsConsistentInIf(false, false), + expected: WhitespaceIsConsistentInTrueElseExpected, + }, + { + name: "whitespace is consistent in a false evaluated if statement", + input: WhitespaceIsConsistentInFalseIf(), + expected: WhitespaceIsConsistentInFalseIfExpected, + }, + { + name: "whitespace is consistent in a switch statement with a true case", + input: WhitespaceIsConsistentInSwitch(1), + expected: WhitespaceIsConsistentInOneSwitchExpected, + }, + { + name: "whitespace is consistent in a switch statement with a default case", + input: WhitespaceIsConsistentInSwitch(2), + expected: WhitespaceIsConsistentInDefaultSwitchExpected, + }, + { + name: "whitespace is consistent in a switch statement with no default case and no true cases", + input: WhitespaceIsConsistentInSwitchNoDefault(), + expected: WhitespaceIsConsistentInSwitchNoDefaultExpected, + }, + { + name: "whitespace is consistent in a for statement that runs 0 times", + input: WhitespaceIsConsistentInFor(0), + expected: WhitespaceIsConsistentInForZeroExpected, + }, + { + name: "whitespace is consistent in a for statement that runs 1 times", + input: WhitespaceIsConsistentInFor(1), + expected: WhitespaceIsConsistentInForOneExpected, + }, + { + name: "whitespace is consistent in a for statement that runs 3 times", + input: WhitespaceIsConsistentInFor(3), + expected: WhitespaceIsConsistentInForThreeExpected, + }, + } { + w := new(strings.Builder) + err := test.input.Render(context.Background(), w) + if err != nil { + t.Errorf("failed to render: %v", err) + } + if diff := cmp.Diff(test.expected, w.String()); diff != "" { + t.Error(diff) + } + } +} diff --git a/templ/generator/test-whitespace-around-go-keywords/template.templ b/templ/generator/test-whitespace-around-go-keywords/template.templ new file mode 100644 index 0000000..91e1376 --- /dev/null +++ b/templ/generator/test-whitespace-around-go-keywords/template.templ @@ -0,0 +1,66 @@ +package testwhitespacearoundgokeywords + +import "fmt" + +templ WhitespaceIsConsistentInIf(firstIf, secondIf bool) { + + if firstIf { + + } else if secondIf { + + } else { + + } + +} + +const WhitespaceIsConsistentInTrueIfExpected = ` ` +const WhitespaceIsConsistentInTrueElseIfExpected = ` ` +const WhitespaceIsConsistentInTrueElseExpected = ` ` + +templ WhitespaceIsConsistentInFalseIf() { + + if false { + + } + +} + +const WhitespaceIsConsistentInFalseIfExpected = ` ` + +templ WhitespaceIsConsistentInSwitch(i int) { + + switch i { + case 1: + + default: + + } + +} + +const WhitespaceIsConsistentInOneSwitchExpected = ` ` +const WhitespaceIsConsistentInDefaultSwitchExpected = ` ` + +templ WhitespaceIsConsistentInSwitchNoDefault() { + + switch false { + case true: + + } + +} + +const WhitespaceIsConsistentInSwitchNoDefaultExpected = ` ` + +templ WhitespaceIsConsistentInFor(i int) { + + for j := 0; j < i; j++ { + + } + +} + +const WhitespaceIsConsistentInForZeroExpected = ` ` +const WhitespaceIsConsistentInForOneExpected = ` ` +const WhitespaceIsConsistentInForThreeExpected = ` ` diff --git a/templ/generator/test-whitespace-around-go-keywords/template_templ.go b/templ/generator/test-whitespace-around-go-keywords/template_templ.go new file mode 100644 index 0000000..58aa130 --- /dev/null +++ b/templ/generator/test-whitespace-around-go-keywords/template_templ.go @@ -0,0 +1,253 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.833 +package testwhitespacearoundgokeywords + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func WhitespaceIsConsistentInIf(firstIf, secondIf bool) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if firstIf { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else if secondIf { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsConsistentInTrueIfExpected = ` ` +const WhitespaceIsConsistentInTrueElseIfExpected = ` ` +const WhitespaceIsConsistentInTrueElseExpected = ` ` + +func WhitespaceIsConsistentInFalseIf() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var2 := templ.GetChildren(ctx) + if templ_7745c5c3_Var2 == nil { + templ_7745c5c3_Var2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if false { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsConsistentInFalseIfExpected = ` ` + +func WhitespaceIsConsistentInSwitch(i int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + switch i { + case 1: + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsConsistentInOneSwitchExpected = ` ` +const WhitespaceIsConsistentInDefaultSwitchExpected = ` ` + +func WhitespaceIsConsistentInSwitchNoDefault() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + switch false { + case true: + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsConsistentInSwitchNoDefaultExpected = ` ` + +func WhitespaceIsConsistentInFor(i int) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for j := 0; j < i; j++ { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +const WhitespaceIsConsistentInForZeroExpected = ` ` +const WhitespaceIsConsistentInForOneExpected = ` ` +const WhitespaceIsConsistentInForThreeExpected = ` ` + +var _ = templruntime.GeneratedTemplate diff --git a/templ/get-version/main.go b/templ/get-version/main.go new file mode 100644 index 0000000..f538f9f --- /dev/null +++ b/templ/get-version/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "log" + "os/exec" + "strconv" + "strings" +) + +func main() { + gitPath, err := exec.LookPath("git") + if err != nil { + log.Fatalf("failed to find git on path: %v", err) + } + + cmd := exec.Command(gitPath, "rev-list", "main", "--count") + output, err := cmd.Output() + if err != nil { + log.Fatalf("failed to run git: %v", err) + } + count, err := strconv.Atoi(strings.TrimSpace(string(output))) + if err != nil { + log.Fatalf("failed to parse git output: %v", err) + } + + // The current commit isn't the one we're about to commit. + fmt.Printf("0.3.%d", count+1) +} diff --git a/templ/go.mod b/templ/go.mod new file mode 100644 index 0000000..d37748d --- /dev/null +++ b/templ/go.mod @@ -0,0 +1,32 @@ +module github.com/a-h/templ + +go 1.23 + +toolchain go1.23.3 + +require ( + github.com/PuerkitoBio/goquery v1.10.1 + github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e + github.com/andybalholm/brotli v1.1.0 + github.com/cenkalti/backoff/v4 v4.3.0 + github.com/cli/browser v1.3.0 + github.com/fatih/color v1.16.0 + github.com/fsnotify/fsnotify v1.7.0 + github.com/google/go-cmp v0.6.0 + github.com/natefinch/atomic v1.0.1 + github.com/rs/cors v1.11.0 + golang.org/x/mod v0.20.0 + golang.org/x/sync v0.10.0 + golang.org/x/tools v0.24.0 +) + +require ( + github.com/andybalholm/cascadia v1.3.3 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect +) + +// replace github.com/a-h/parse => /Users/adrian/github.com/a-h/parse diff --git a/templ/go.sum b/templ/go.sum new file mode 100644 index 0000000..3e9cf9d --- /dev/null +++ b/templ/go.sum @@ -0,0 +1,102 @@ +github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU= +github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY= +github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e h1:Eog54DQpku7NpPNff9wzQYT61TGu9jjq5N8UhAkqIgw= +github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e/go.mod h1:FMIm5afKmEfarNbIXOaPHFY8X7fo+fRQB6I9MPG2nB0= +github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo= +github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= +github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo= +github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/templ/handler.go b/templ/handler.go new file mode 100644 index 0000000..a28d561 --- /dev/null +++ b/templ/handler.go @@ -0,0 +1,102 @@ +package templ + +import "net/http" + +// ComponentHandler is a http.Handler that renders components. +type ComponentHandler struct { + Component Component + Status int + ContentType string + ErrorHandler func(r *http.Request, err error) http.Handler + StreamResponse bool +} + +const componentHandlerErrorMessage = "templ: failed to render template" + +func (ch *ComponentHandler) ServeHTTPBuffered(w http.ResponseWriter, r *http.Request) { + // Since the component may error, write to a buffer first. + // This prevents partial responses from being written to the client. + buf := GetBuffer() + defer ReleaseBuffer(buf) + err := ch.Component.Render(r.Context(), buf) + if err != nil { + if ch.ErrorHandler != nil { + w.Header().Set("Content-Type", ch.ContentType) + ch.ErrorHandler(r, err).ServeHTTP(w, r) + return + } + http.Error(w, componentHandlerErrorMessage, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", ch.ContentType) + if ch.Status != 0 { + w.WriteHeader(ch.Status) + } + // Ignore write error like http.Error() does, because there is + // no way to recover at this point. + _, _ = w.Write(buf.Bytes()) +} + +func (ch *ComponentHandler) ServeHTTPStreamed(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", ch.ContentType) + if ch.Status != 0 { + w.WriteHeader(ch.Status) + } + if err := ch.Component.Render(r.Context(), w); err != nil { + if ch.ErrorHandler != nil { + w.Header().Set("Content-Type", ch.ContentType) + ch.ErrorHandler(r, err).ServeHTTP(w, r) + return + } + http.Error(w, componentHandlerErrorMessage, http.StatusInternalServerError) + } +} + +// ServeHTTP implements the http.Handler interface. +func (ch ComponentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if ch.StreamResponse { + ch.ServeHTTPStreamed(w, r) + return + } + ch.ServeHTTPBuffered(w, r) +} + +// Handler creates a http.Handler that renders the template. +func Handler(c Component, options ...func(*ComponentHandler)) *ComponentHandler { + ch := &ComponentHandler{ + Component: c, + ContentType: "text/html; charset=utf-8", + } + for _, o := range options { + o(ch) + } + return ch +} + +// WithStatus sets the HTTP status code returned by the ComponentHandler. +func WithStatus(status int) func(*ComponentHandler) { + return func(ch *ComponentHandler) { + ch.Status = status + } +} + +// WithContentType sets the Content-Type header returned by the ComponentHandler. +func WithContentType(contentType string) func(*ComponentHandler) { + return func(ch *ComponentHandler) { + ch.ContentType = contentType + } +} + +// WithErrorHandler sets the error handler used if rendering fails. +func WithErrorHandler(eh func(r *http.Request, err error) http.Handler) func(*ComponentHandler) { + return func(ch *ComponentHandler) { + ch.ErrorHandler = eh + } +} + +// WithStreaming sets the ComponentHandler to stream the response instead of buffering it. +func WithStreaming() func(*ComponentHandler) { + return func(ch *ComponentHandler) { + ch.StreamResponse = true + } +} diff --git a/templ/handler_test.go b/templ/handler_test.go new file mode 100644 index 0000000..b3f3658 --- /dev/null +++ b/templ/handler_test.go @@ -0,0 +1,207 @@ +package templ_test + +import ( + "context" + "errors" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestHandler(t *testing.T) { + hello := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + if _, err := io.WriteString(w, "Hello"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + return nil + }) + errorComponent := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + if _, err := io.WriteString(w, "Hello"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + return errors.New("handler error") + }) + + tests := []struct { + name string + input *templ.ComponentHandler + expectedStatus int + expectedMIMEType string + expectedBody string + }{ + { + name: "handlers return OK by default", + input: templ.Handler(hello), + expectedStatus: http.StatusOK, + expectedMIMEType: "text/html; charset=utf-8", + expectedBody: "Hello", + }, + { + name: "handlers return OK by default", + input: templ.Handler(templ.Raw(`♠ ‘ ♠ ‘`)), + expectedStatus: http.StatusOK, + expectedMIMEType: "text/html; charset=utf-8", + expectedBody: "♠ ‘ ♠ ‘", + }, + { + name: "handlers can be configured to return an alternative status code", + input: templ.Handler(hello, templ.WithStatus(http.StatusNotFound)), + expectedStatus: http.StatusNotFound, + expectedMIMEType: "text/html; charset=utf-8", + expectedBody: "Hello", + }, + { + name: "handlers can be configured to return an alternative status code and content type", + input: templ.Handler(hello, templ.WithStatus(http.StatusOK), templ.WithContentType("text/csv")), + expectedStatus: http.StatusOK, + expectedMIMEType: "text/csv", + expectedBody: "Hello", + }, + { + name: "handlers that fail return a 500 error", + input: templ.Handler(errorComponent), + expectedStatus: http.StatusInternalServerError, + expectedMIMEType: "text/plain; charset=utf-8", + expectedBody: "templ: failed to render template\n", + }, + { + name: "error handling can be customised", + input: templ.Handler(errorComponent, templ.WithErrorHandler(func(r *http.Request, err error) http.Handler { + // Because the error is received, it's possible to log the detail of the request. + // log.Printf("template render error for %v %v: %v", r.Method, r.URL.String(), err) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadRequest) + if _, err := io.WriteString(w, "custom body"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + }) + })), + expectedStatus: http.StatusBadRequest, + expectedMIMEType: "text/html; charset=utf-8", + expectedBody: "custom body", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/test", nil) + tt.input.ServeHTTP(w, r) + if got := w.Result().StatusCode; tt.expectedStatus != got { + t.Errorf("expected status %d, got %d", tt.expectedStatus, got) + } + if mimeType := w.Result().Header.Get("Content-Type"); tt.expectedMIMEType != mimeType { + t.Errorf("expected content-type %s, got %s", tt.expectedMIMEType, mimeType) + } + body, err := io.ReadAll(w.Result().Body) + if err != nil { + t.Errorf("failed to read body: %v", err) + } + if diff := cmp.Diff(tt.expectedBody, string(body)); diff != "" { + t.Error(diff) + } + }) + } + + t.Run("streaming mode allows responses to be flushed", func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/test", nil) + + component := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + // Write part 1. + if _, err := io.WriteString(w, "Part 1"); err != nil { + return err + } + // Flush. + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + // Check partial response. + wr := w.(*httptest.ResponseRecorder) + actualBody := wr.Body.String() + if diff := cmp.Diff("Part 1", actualBody); diff != "" { + t.Error(diff) + } + // Write part 2. + if _, err := io.WriteString(w, "\nPart 2"); err != nil { + return err + } + return nil + }) + + templ.Handler(component, templ.WithStatus(http.StatusCreated), templ.WithStreaming()).ServeHTTP(w, r) + if got := w.Result().StatusCode; http.StatusCreated != got { + t.Errorf("expected status %d, got %d", http.StatusCreated, got) + } + if mimeType := w.Result().Header.Get("Content-Type"); "text/html; charset=utf-8" != mimeType { + t.Errorf("expected content-type %s, got %s", "text/html; charset=utf-8", mimeType) + } + body, err := io.ReadAll(w.Result().Body) + if err != nil { + t.Errorf("failed to read body: %v", err) + } + if diff := cmp.Diff("Part 1\nPart 2", string(body)); diff != "" { + t.Error(diff) + } + }) + t.Run("streaming mode handles errors", func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest("GET", "/test", nil) + + expectedErr := errors.New("streaming error") + + component := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + if _, err := io.WriteString(w, "Body"); err != nil { + return err + } + return expectedErr + }) + + var errorHandlerCalled bool + errorHandler := func(r *http.Request, err error) http.Handler { + if expectedErr != err { + t.Errorf("expected error %v, got %v", expectedErr, err) + } + errorHandlerCalled = true + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // This will be ignored, because the header has already been written. + w.WriteHeader(http.StatusBadRequest) + // This will be written, but will be appended to the written body. + if _, err := io.WriteString(w, "Error message"); err != nil { + t.Errorf("failed to write error message: %v", err) + } + }) + } + + h := templ.Handler(component, + templ.WithStatus(http.StatusCreated), + templ.WithStreaming(), + templ.WithErrorHandler(errorHandler), + ) + h.ServeHTTP(w, r) + + if !errorHandlerCalled { + t.Error("expected error handler to be called") + } + // Expect the status code to be 201, not 400, because in streaming mode, + // we have to write the header before we can call the error handler. + if actualResponseCode := w.Result().StatusCode; http.StatusCreated != actualResponseCode { + t.Errorf("expected status %d, got %d", http.StatusCreated, actualResponseCode) + } + // Expect the body to be "BodyError message", not just "Error message" because + // in streaming mode, we've already written part of the body to the response, unlike in + // standard mode where the body is written to a buffer before the response is written, + // ensuring that partial responses are not sent. + actualBody, err := io.ReadAll(w.Result().Body) + if err != nil { + t.Errorf("failed to read body: %v", err) + } + if diff := cmp.Diff("BodyError message", string(actualBody)); diff != "" { + t.Error(diff) + } + }) +} diff --git a/templ/ide-demo.gif b/templ/ide-demo.gif new file mode 100644 index 0000000..e35fd68 Binary files /dev/null and b/templ/ide-demo.gif differ diff --git a/templ/join.go b/templ/join.go new file mode 100644 index 0000000..a809359 --- /dev/null +++ b/templ/join.go @@ -0,0 +1,19 @@ +package templ + +import ( + "context" + "io" +) + +// Join returns a single `templ.Component` that will render provided components in order. +// If any of the components return an error the Join component will immediately return with the error. +func Join(components ...Component) Component { + return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + for _, c := range components { + if err = c.Render(ctx, w); err != nil { + return err + } + } + return nil + }) +} diff --git a/templ/join_test.go b/templ/join_test.go new file mode 100644 index 0000000..a0572f9 --- /dev/null +++ b/templ/join_test.go @@ -0,0 +1,81 @@ +package templ_test + +import ( + "bytes" + "context" + "errors" + "io" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestJoin(t *testing.T) { + compErr := errors.New("component error") + + hello := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + if _, err := io.WriteString(w, "Hello"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + return nil + }) + world := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + if _, err := io.WriteString(w, "World"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + return nil + }) + err := templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + return compErr + }) + + tests := []struct { + name string + input []templ.Component + expectedOutput string + expectedErr error + }{ + { + name: "a nil slice of components produces no output", + input: nil, + expectedOutput: "", + }, + { + name: "an empty list of components produces no output", + input: []templ.Component{}, + expectedOutput: "", + }, + { + name: "components are rendered in order", + input: []templ.Component{hello, world}, + expectedOutput: "HelloWorld", + }, + { + name: "components are rendered in order, and errors returned", + input: []templ.Component{hello, err}, + expectedOutput: "Hello", + expectedErr: compErr, + }, + { + name: "no further components are rendered after an error", + input: []templ.Component{err, hello}, + expectedOutput: "", + expectedErr: compErr, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := templ.Join(tt.input...) + b := new(bytes.Buffer) + err := got.Render(context.Background(), b) + if err != tt.expectedErr { + t.Fatalf("failed to render component: %v", err) + } + if diff := cmp.Diff(tt.expectedOutput, b.String()); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/js.go b/templ/js.go new file mode 100644 index 0000000..f07f7ff --- /dev/null +++ b/templ/js.go @@ -0,0 +1,40 @@ +package templ + +import ( + "crypto/sha256" + "encoding/hex" + "html" +) + +// JSUnsafeFuncCall calls arbitrary JavaScript in the js parameter. +// +// Use of this function presents a security risk - the JavaScript must come +// from a trusted source, because it will be included as-is in the output. +func JSUnsafeFuncCall[T ~string](js T) ComponentScript { + sum := sha256.Sum256([]byte(js)) + return ComponentScript{ + Name: "jsUnsafeFuncCall_" + hex.EncodeToString(sum[:]), + // Function is empty because the body of the function is defined elsewhere, + // e.g. in a `, + }, + { + name: "single argument is supported", + functionName: "alert", + args: []any{"hello"}, + expected: ComponentScript{ + Name: "jsFuncCall_92df7244f17dc5bfc41dfd02043df695e4664f8bf42c265a46d79b32b97693d0", + Function: "", + Call: "alert("hello")", + CallInline: `alert("hello")`, + }, + expectedComponentOutput: ``, + }, + { + name: "multiple arguments are supported", + functionName: "console.log", + args: []any{"hello", "world"}, + expected: ComponentScript{ + Name: "jsFuncCall_2b3416c14fc2700d01e0013e7b7076bb8dd5f3126d19e2e801de409163e3960c", + Function: "", + Call: "console.log("hello","world")", + CallInline: `console.log("hello","world")`, + }, + expectedComponentOutput: ``, + }, + { + name: "attribute injection fails", + functionName: `" onmouseover="alert('hello')`, + args: nil, + expected: ComponentScript{ + Name: "jsFuncCall_e56d1214f3b4fbf27406f209e3f4a58c2842fa2760b6d83da5ee72e04c89f913", + Function: "", + Call: "__templ_invalid_js_function_name()", + CallInline: "__templ_invalid_js_function_name()", + }, + expectedComponentOutput: ``, + }, + { + name: "closing the script and injecting HTML fails", + functionName: `
    Hello
    `, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + // Test creation. + actual := JSFuncCall(tt.functionName, tt.args...) + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + + // Test rendering. + buf := new(bytes.Buffer) + err := actual.Render(context.Background(), buf) + if err != nil { + t.Error(err) + } + if diff := cmp.Diff(tt.expectedComponentOutput, buf.String()); diff != "" { + t.Error(diff) + } + + }) + } +} + +func TestJSFunctionNameRegexp(t *testing.T) { + tests := []struct { + input string + expected bool + }{ + { + input: "console.log", + expected: true, + }, + { + input: "alert", + expected: true, + }, + { + input: "console.log('hello')", + expected: false, + }, + { + input: "
    Hello
    +func JSONScript(id string, data any) JSONScriptElement { + return JSONScriptElement{ + ID: id, + Type: "application/json", + Data: data, + Nonce: GetNonce, + } +} + +// WithType sets the value of the type attribute of the script element. +func (j JSONScriptElement) WithType(t string) JSONScriptElement { + j.Type = t + return j +} + +// WithNonceFromString sets the value of the nonce attribute of the script element to the given string. +func (j JSONScriptElement) WithNonceFromString(nonce string) JSONScriptElement { + j.Nonce = func(context.Context) string { + return nonce + } + return j +} + +// WithNonceFrom sets the value of the nonce attribute of the script element to the value returned by the given function. +func (j JSONScriptElement) WithNonceFrom(f func(context.Context) string) JSONScriptElement { + j.Nonce = f + return j +} + +type JSONScriptElement struct { + // ID of the element in the DOM. + ID string + // Type of the script element, defaults to "application/json". + Type string + // Data that will be encoded as JSON. + Data any + // Nonce is a function that returns a CSP nonce. + // Defaults to CSPNonceFromContext. + // See https://content-security-policy.com/nonce for more information. + Nonce func(ctx context.Context) string +} + +func (j JSONScriptElement) Render(ctx context.Context, w io.Writer) (err error) { + if _, err = io.WriteString(w, ""); err != nil { + return err + } + if err = json.NewEncoder(w).Encode(j.Data); err != nil { + return err + } + if _, err = io.WriteString(w, ""); err != nil { + return err + } + return nil +} diff --git a/templ/jsonscript_test.go b/templ/jsonscript_test.go new file mode 100644 index 0000000..e6ad961 --- /dev/null +++ b/templ/jsonscript_test.go @@ -0,0 +1,58 @@ +package templ_test + +import ( + "bytes" + "context" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestJSONScriptElement(t *testing.T) { + data := map[string]any{"foo": "bar"} + tests := []struct { + name string + ctx context.Context + e templ.JSONScriptElement + expected string + }{ + { + name: "renders data as JSON inside a script element", + e: templ.JSONScript("id", data), + expected: "", + }, + { + name: "if a nonce is available in the context, it is used", + ctx: templ.WithNonce(context.Background(), "nonce-from-context"), + e: templ.JSONScript("idc", data), + expected: "", + }, + { + name: "if a nonce is provided, it is used", + e: templ.JSONScript("ids", data).WithNonceFromString("nonce-from-string"), + expected: "", + }, + { + name: "if a nonce function is provided, it is used", + e: templ.JSONScript("idf", data).WithNonceFrom(func(context.Context) string { return "nonce-from-function" }), + expected: "", + }, + { + name: "if a type is provided, it is used", + e: templ.JSONScript("idt", data).WithType("application/ld+json"), + expected: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := new(bytes.Buffer) + if err := tt.e.Render(tt.ctx, w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff(tt.expected, w.String()); diff != "" { + t.Fatalf("unexpected output (-want +got):\n%s", diff) + } + }) + } +} diff --git a/templ/jsonstring.go b/templ/jsonstring.go new file mode 100644 index 0000000..425e4e8 --- /dev/null +++ b/templ/jsonstring.go @@ -0,0 +1,14 @@ +package templ + +import ( + "encoding/json" +) + +// JSONString returns a JSON encoded string of v. +func JSONString(v any) (string, error) { + b, err := json.Marshal(v) + if err != nil { + return "", err + } + return string(b), nil +} diff --git a/templ/jsonstring_test.go b/templ/jsonstring_test.go new file mode 100644 index 0000000..b40c31e --- /dev/null +++ b/templ/jsonstring_test.go @@ -0,0 +1,28 @@ +package templ_test + +import ( + "testing" + + "github.com/a-h/templ" +) + +func TestJSONString(t *testing.T) { + t.Run("renders input data as a JSON string", func(t *testing.T) { + data := map[string]any{"foo": "bar"} + actual, err := templ.JSONString(data) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expected := "{\"foo\":\"bar\"}" + if actual != expected { + t.Fatalf("unexpected output: want %q, got %q", expected, actual) + } + }) + t.Run("returns an error if the data cannot be marshalled", func(t *testing.T) { + data := make(chan int) + _, err := templ.JSONString(data) + if err == nil { + t.Fatalf("expected an error, got nil") + } + }) +} diff --git a/templ/logo/logo.svg b/templ/logo/logo.svg new file mode 100644 index 0000000..a15d445 --- /dev/null +++ b/templ/logo/logo.svg @@ -0,0 +1,86 @@ + + + + + + + + + + </> TEMPL + + diff --git a/templ/lsp/LICENSE b/templ/lsp/LICENSE new file mode 100644 index 0000000..e874870 --- /dev/null +++ b/templ/lsp/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2019, The Go Language Server Authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/templ/lsp/README.md b/templ/lsp/README.md new file mode 100644 index 0000000..2114d15 --- /dev/null +++ b/templ/lsp/README.md @@ -0,0 +1,3 @@ +# lsp + +Forked from https://github.com/go-language-server repos. diff --git a/templ/lsp/jsonrpc2/codes.go b/templ/lsp/jsonrpc2/codes.go new file mode 100644 index 0000000..5da58ea --- /dev/null +++ b/templ/lsp/jsonrpc2/codes.go @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +// Code is an error code as defined in the JSON-RPC spec. +type Code int32 + +// list of JSON-RPC error codes. +const ( + // ParseError is the invalid JSON was received by the server. + // An error occurred on the server while parsing the JSON text. + ParseError Code = -32700 + + // InvalidRequest is the JSON sent is not a valid Request object. + InvalidRequest Code = -32600 + + // MethodNotFound is the method does not exist / is not available. + MethodNotFound Code = -32601 + + // InvalidParams is the invalid method parameter(s). + InvalidParams Code = -32602 + + // InternalError is the internal JSON-RPC error. + InternalError Code = -32603 + + // JSONRPCReservedErrorRangeStart is the start range of JSON RPC reserved error codes. + // + // It doesn't denote a real error code. No LSP error codes should + // be defined between the start and end range. For backwards + // compatibility the "ServerNotInitialized" and the "UnknownErrorCode" + // are left in the range. + // + // @since 3.16.0. + JSONRPCReservedErrorRangeStart Code = -32099 + + // CodeServerErrorStart reserved for implementation-defined server-errors. + // + // Deprecated: Use JSONRPCReservedErrorRangeStart instead. + CodeServerErrorStart = JSONRPCReservedErrorRangeStart + + // ServerNotInitialized is the error of server not initialized. + ServerNotInitialized Code = -32002 + + // UnknownError should be used for all non coded errors. + UnknownError Code = -32001 + + // JSONRPCReservedErrorRangeEnd is the start range of JSON RPC reserved error codes. + // + // It doesn't denote a real error code. + // + // @since 3.16.0. + JSONRPCReservedErrorRangeEnd Code = -32000 + + // CodeServerErrorEnd reserved for implementation-defined server-errors. + // + // Deprecated: Use JSONRPCReservedErrorRangeEnd instead. + CodeServerErrorEnd = JSONRPCReservedErrorRangeEnd +) + +// This file contains the Go forms of the wire specification. +// +// See http://www.jsonrpc.org/specification for details. +// +// list of JSON-RPC errors. +var ( + // ErrUnknown should be used for all non coded errors. + ErrUnknown = NewError(UnknownError, "JSON-RPC unknown error") + + // ErrParse is used when invalid JSON was received by the server. + ErrParse = NewError(ParseError, "JSON-RPC parse error") + + // ErrInvalidRequest is used when the JSON sent is not a valid Request object. + ErrInvalidRequest = NewError(InvalidRequest, "JSON-RPC invalid request") + + // ErrMethodNotFound should be returned by the handler when the method does + // not exist / is not available. + ErrMethodNotFound = NewError(MethodNotFound, "JSON-RPC method not found") + + // ErrInvalidParams should be returned by the handler when method + // parameter(s) were invalid. + ErrInvalidParams = NewError(InvalidParams, "JSON-RPC invalid params") + + // ErrInternal is not currently returned but defined for completeness. + ErrInternal = NewError(InternalError, "JSON-RPC internal error") +) diff --git a/templ/lsp/jsonrpc2/conn.go b/templ/lsp/jsonrpc2/conn.go new file mode 100644 index 0000000..8757f5e --- /dev/null +++ b/templ/lsp/jsonrpc2/conn.go @@ -0,0 +1,244 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "bytes" + "context" + "fmt" + "sync" + "sync/atomic" + + "encoding/json" +) + +// Conn is the common interface to jsonrpc clients and servers. +// +// Conn is bidirectional; it does not have a designated server or client end. +// It manages the jsonrpc2 protocol, connecting responses back to their calls. +type Conn interface { + // Call invokes the target method and waits for a response. + // + // The params will be marshaled to JSON before sending over the wire, and will + // be handed to the method invoked. + // + // The response will be unmarshaled from JSON into the result. + // + // The id returned will be unique from this connection, and can be used for + // logging or tracking. + Call(ctx context.Context, method string, params, result any) (ID, error) + + // Notify invokes the target method but does not wait for a response. + // + // The params will be marshaled to JSON before sending over the wire, and will + // be handed to the method invoked. + Notify(ctx context.Context, method string, params any) error + + // Go starts a goroutine to handle the connection. + // + // It must be called exactly once for each Conn. It returns immediately. + // Must block on Done() to wait for the connection to shut down. + // + // This is a temporary measure, this should be started automatically in the + // future. + Go(ctx context.Context, handler Handler) + + // Close closes the connection and it's underlying stream. + // + // It does not wait for the close to complete, use the Done() channel for + // that. + Close() error + + // Done returns a channel that will be closed when the processing goroutine + // has terminated, which will happen if Close() is called or an underlying + // stream is closed. + Done() <-chan struct{} + + // Err returns an error if there was one from within the processing goroutine. + // + // If err returns non nil, the connection will be already closed or closing. + Err() error +} + +type conn struct { + seq int32 // access atomically + writeMu sync.Mutex // protects writes to the stream + stream Stream // supplied stream + pendingMu sync.Mutex // protects the pending map + pending map[ID]chan *Response // holds the pending response channel with the ID as the key. + + done chan struct{} // closed when done + err atomic.Value // holds run error +} + +// NewConn creates a new connection object around the supplied stream. +func NewConn(s Stream) Conn { + conn := &conn{ + stream: s, + pending: make(map[ID]chan *Response), + done: make(chan struct{}), + } + return conn +} + +// Call implements Conn. +func (c *conn) Call(ctx context.Context, method string, params, result any) (id ID, err error) { + // generate a new request identifier + id = NewNumberID(atomic.AddInt32(&c.seq, 1)) + call, err := NewCall(id, method, params) + if err != nil { + return id, fmt.Errorf("marshaling call parameters: %w", err) + } + + // We have to add ourselves to the pending map before we send, otherwise we + // are racing the response. Also add a buffer to rchan, so that if we get a + // wire response between the time this call is cancelled and id is deleted + // from c.pending, the send to rchan will not block. + rchan := make(chan *Response, 1) + + c.pendingMu.Lock() + c.pending[id] = rchan + c.pendingMu.Unlock() + + defer func() { + c.pendingMu.Lock() + delete(c.pending, id) + c.pendingMu.Unlock() + }() + + // now we are ready to send + _, err = c.write(ctx, call) + if err != nil { + // sending failed, we will never get a response, so don't leave it pending + return id, err + } + + // now wait for the response + select { + case resp := <-rchan: + // is it an error response? + if resp.err != nil { + return id, resp.err + } + + if result == nil || len(resp.result) == 0 { + return id, nil + } + + dec := json.NewDecoder(bytes.NewReader(resp.result)) + if err := dec.Decode(result); err != nil { + return id, fmt.Errorf("unmarshaling result: %w", err) + } + + return id, nil + + case <-ctx.Done(): + return id, ctx.Err() + } +} + +// Notify implements Conn. +func (c *conn) Notify(ctx context.Context, method string, params any) (err error) { + notify, err := NewNotification(method, params) + if err != nil { + return fmt.Errorf("marshaling notify parameters: %w", err) + } + + _, err = c.write(ctx, notify) + + return err +} + +func (c *conn) replier(req Message) Replier { + return func(ctx context.Context, result any, err error) error { + call, ok := req.(*Call) + if !ok { + // request was a notify, no need to respond + return nil + } + + response, err := NewResponse(call.id, result, err) + if err != nil { + return err + } + + _, err = c.write(ctx, response) + if err != nil { + // TODO(iancottrell): if a stream write fails, we really need to shut down the whole stream + return err + } + return nil + } +} + +func (c *conn) write(ctx context.Context, msg Message) (int64, error) { + c.writeMu.Lock() + n, err := c.stream.Write(ctx, msg) + c.writeMu.Unlock() + if err != nil { + return 0, fmt.Errorf("write to stream: %w", err) + } + + return n, nil +} + +// Go implements Conn. +func (c *conn) Go(ctx context.Context, handler Handler) { + go c.run(ctx, handler) +} + +func (c *conn) run(ctx context.Context, handler Handler) { + defer close(c.done) + + for { + // get the next message + msg, _, err := c.stream.Read(ctx) + if err != nil { + // The stream failed, we cannot continue. + c.fail(err) + return + } + + switch msg := msg.(type) { + case Request: + if err := handler(ctx, c.replier(msg), msg); err != nil { + c.fail(err) + } + + case *Response: + // If method is not set, this should be a response, in which case we must + // have an id to send the response back to the caller. + c.pendingMu.Lock() + rchan, ok := c.pending[msg.id] + c.pendingMu.Unlock() + if ok { + rchan <- msg + } + } + } +} + +// Close implements Conn. +func (c *conn) Close() error { + return c.stream.Close() +} + +// Done implements Conn. +func (c *conn) Done() <-chan struct{} { + return c.done +} + +// Err implements Conn. +func (c *conn) Err() error { + if err := c.err.Load(); err != nil { + return err.(error) + } + return nil +} + +// fail sets a failure condition on the stream and closes it. +func (c *conn) fail(err error) { + c.err.Store(err) + c.stream.Close() +} diff --git a/templ/lsp/jsonrpc2/errors.go b/templ/lsp/jsonrpc2/errors.go new file mode 100644 index 0000000..ce8427b --- /dev/null +++ b/templ/lsp/jsonrpc2/errors.go @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "errors" + "fmt" + + "encoding/json" +) + +// Error represents a JSON-RPC error. +type Error struct { + // Code a number indicating the error type that occurred. + Code Code `json:"code"` + + // Message a string providing a short description of the error. + Message string `json:"message"` + + // Data a Primitive or Structured value that contains additional + // information about the error. Can be omitted. + Data *json.RawMessage `json:"data,omitempty"` +} + +// compile time check whether the Error implements error interface. +var _ error = (*Error)(nil) + +// Error implements error.Error. +func (e *Error) Error() string { + if e == nil { + return "" + } + return e.Message +} + +// Unwrap implements errors.Unwrap. +// +// Returns the error underlying the receiver, which may be nil. +func (e *Error) Unwrap() error { return errors.New(e.Message) } + +// NewError builds a Error struct for the suppied code and message. +func NewError(c Code, message string) *Error { + return &Error{ + Code: c, + Message: message, + } +} + +// Errorf builds a Error struct for the suppied code, format and args. +func Errorf(c Code, format string, args ...any) *Error { + return &Error{ + Code: c, + Message: fmt.Sprintf(format, args...), + } +} + +// constErr represents a error constant. +type constErr string + +// compile time check whether the constErr implements error interface. +var _ error = (*constErr)(nil) + +// Error implements error.Error. +func (e constErr) Error() string { return string(e) } + +const ( + // ErrIdleTimeout is returned when serving timed out waiting for new connections. + ErrIdleTimeout = constErr("timed out waiting for new connections") +) diff --git a/templ/lsp/jsonrpc2/handler.go b/templ/lsp/jsonrpc2/handler.go new file mode 100644 index 0000000..4992979 --- /dev/null +++ b/templ/lsp/jsonrpc2/handler.go @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "context" + "fmt" + "sync" +) + +// Handler is invoked to handle incoming requests. +// +// The Replier sends a reply to the request and must be called exactly once. +type Handler func(ctx context.Context, reply Replier, req Request) error + +// Replier is passed to handlers to allow them to reply to the request. +// +// If err is set then result will be ignored. +type Replier func(ctx context.Context, result any, err error) error + +// MethodNotFoundHandler is a Handler that replies to all call requests with the +// standard method not found response. +// +// This should normally be the final handler in a chain. +func MethodNotFoundHandler(ctx context.Context, reply Replier, req Request) error { + return reply(ctx, nil, fmt.Errorf("%q: %w", req.Method(), ErrMethodNotFound)) +} + +// ReplyHandler creates a Handler that panics if the wrapped handler does +// not call Reply for every request that it is passed. +func ReplyHandler(handler Handler) (h Handler) { + h = Handler(func(ctx context.Context, reply Replier, req Request) error { + called := false + err := handler(ctx, func(ctx context.Context, result any, err error) error { + if called { + panic(fmt.Errorf("request %q replied to more than once", req.Method())) + } + called = true + + return reply(ctx, result, err) + }, req) + if !called { + panic(fmt.Errorf("request %q was never replied to", req.Method())) + } + return err + }) + + return h +} + +// CancelHandler returns a handler that supports cancellation, and a function +// that can be used to trigger canceling in progress requests. +func CancelHandler(handler Handler) (h Handler, canceller func(id ID)) { + var mu sync.Mutex + handling := make(map[ID]context.CancelFunc) + + h = Handler(func(ctx context.Context, reply Replier, req Request) error { + if call, ok := req.(*Call); ok { + cancelCtx, cancel := context.WithCancel(ctx) + ctx = cancelCtx + + mu.Lock() + handling[call.ID()] = cancel + mu.Unlock() + + innerReply := reply + reply = func(ctx context.Context, result any, err error) error { + mu.Lock() + delete(handling, call.ID()) + mu.Unlock() + return innerReply(ctx, result, err) + } + } + return handler(ctx, reply, req) + }) + + canceller = func(id ID) { + mu.Lock() + cancel, found := handling[id] + mu.Unlock() + if found { + cancel() + } + } + + return h, canceller +} + +// AsyncHandler returns a handler that processes each request goes in its own +// goroutine. +// +// The handler returns immediately, without the request being processed. +// Each request then waits for the previous request to finish before it starts. +// +// This allows the stream to unblock at the cost of unbounded goroutines +// all stalled on the previous one. +func AsyncHandler(handler Handler) (h Handler) { + nextRequest := make(chan struct{}) + close(nextRequest) + + h = Handler(func(ctx context.Context, reply Replier, req Request) error { + waitForPrevious := nextRequest + nextRequest = make(chan struct{}) + unlockNext := nextRequest + innerReply := reply + reply = func(ctx context.Context, result any, err error) error { + close(unlockNext) + return innerReply(ctx, result, err) + } + + go func() { + <-waitForPrevious + _ = handler(ctx, reply, req) + }() + return nil + }) + + return h +} diff --git a/templ/lsp/jsonrpc2/jsonrpc2.go b/templ/lsp/jsonrpc2/jsonrpc2.go new file mode 100644 index 0000000..ff428cc --- /dev/null +++ b/templ/lsp/jsonrpc2/jsonrpc2.go @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +// Package jsonrpc2 is an implementation of the JSON-RPC 2 specification for Go. +// +// https://www.jsonrpc.org/specification +package jsonrpc2 // import "github.com/a-h/templ/lsp/jsonrpc2" diff --git a/templ/lsp/jsonrpc2/jsonrpc2_test.go b/templ/lsp/jsonrpc2/jsonrpc2_test.go new file mode 100644 index 0000000..42de66c --- /dev/null +++ b/templ/lsp/jsonrpc2/jsonrpc2_test.go @@ -0,0 +1,171 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2_test + +import ( + "bytes" + "context" + "fmt" + "io" + "net" + "path" + "reflect" + "testing" + + "encoding/json" + + "github.com/a-h/templ/lsp/jsonrpc2" +) + +const ( + methodNoArgs = "no_args" + methodOneString = "one_string" + methodOneNumber = "one_number" + methodJoin = "join" +) + +type callTest struct { + method string + params any + expect any +} + +var callTests = []callTest{ + { + method: methodNoArgs, + params: nil, + expect: true, + }, + { + method: methodOneString, + params: "fish", + expect: "got:fish", + }, + { + method: methodOneNumber, + params: 10, + expect: "got:10", + }, + { + method: methodJoin, + params: []string{"a", "b", "c"}, + expect: "a/b/c", + }, + // TODO: expand the test cases +} + +func (test *callTest) newResults() any { + switch e := test.expect.(type) { + case []any: + var r []any + for _, v := range e { + r = append(r, reflect.New(reflect.TypeOf(v)).Interface()) + } + return r + + case nil: + return nil + + default: + return reflect.New(reflect.TypeOf(test.expect)).Interface() + } +} + +func (test *callTest) verifyResults(t *testing.T, results any) { + t.Helper() + + if results == nil { + return + } + + val := reflect.Indirect(reflect.ValueOf(results)).Interface() + if !reflect.DeepEqual(val, test.expect) { + t.Errorf("%v:Results are incorrect, got %+v expect %+v", test.method, val, test.expect) + } +} + +func TestRequest(t *testing.T) { + ctx := context.Background() + a, b, done := prepare(ctx, t) + defer done() + + for _, test := range callTests { + t.Run(test.method, func(t *testing.T) { + results := test.newResults() + if _, err := a.Call(ctx, test.method, test.params, results); err != nil { + t.Fatalf("%v:Call failed: %v", test.method, err) + } + test.verifyResults(t, results) + + if _, err := b.Call(ctx, test.method, test.params, results); err != nil { + t.Fatalf("%v:Call failed: %v", test.method, err) + } + test.verifyResults(t, results) + }) + } +} + +func prepare(ctx context.Context, t *testing.T) (a, b jsonrpc2.Conn, done func()) { + t.Helper() + + // make a wait group that can be used to wait for the system to shut down + aPipe, bPipe := net.Pipe() + a = run(ctx, aPipe) + b = run(ctx, bPipe) + done = func() { + a.Close() + b.Close() + <-a.Done() + <-b.Done() + } + + return a, b, done +} + +func run(ctx context.Context, nc io.ReadWriteCloser) jsonrpc2.Conn { + stream := jsonrpc2.NewStream(nc) + conn := jsonrpc2.NewConn(stream) + conn.Go(ctx, testHandler()) + + return conn +} + +func testHandler() jsonrpc2.Handler { + return func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { + switch req.Method() { + case methodNoArgs: + if len(req.Params()) > 0 { + return reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + return reply(ctx, true, nil) + + case methodOneString: + var v string + dec := json.NewDecoder(bytes.NewReader(req.Params())) + if err := dec.Decode(&v); err != nil { + return reply(ctx, nil, fmt.Errorf("%s: %w", jsonrpc2.ErrParse, err)) + } + return reply(ctx, "got:"+v, nil) + + case methodOneNumber: + var v int + dec := json.NewDecoder(bytes.NewReader(req.Params())) + if err := dec.Decode(&v); err != nil { + return reply(ctx, nil, fmt.Errorf("%s: %w", jsonrpc2.ErrParse, err)) + } + return reply(ctx, fmt.Sprintf("got:%d", v), nil) + + case methodJoin: + var v []string + dec := json.NewDecoder(bytes.NewReader(req.Params())) + if err := dec.Decode(&v); err != nil { + return reply(ctx, nil, fmt.Errorf("%s: %w", jsonrpc2.ErrParse, err)) + } + return reply(ctx, path.Join(v...), nil) + + default: + return jsonrpc2.MethodNotFoundHandler(ctx, reply, req) + } + } +} diff --git a/templ/lsp/jsonrpc2/message.go b/templ/lsp/jsonrpc2/message.go new file mode 100644 index 0000000..6ea146b --- /dev/null +++ b/templ/lsp/jsonrpc2/message.go @@ -0,0 +1,354 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "bytes" + "errors" + "fmt" + + "encoding/json" +) + +// Message is the interface to all JSON-RPC message types. +// +// They share no common functionality, but are a closed set of concrete types +// that are allowed to implement this interface. +// +// The message types are *Call, *Response and *Notification. +type Message interface { + // jsonrpc2Message is used to make the set of message implementations a + // closed set. + jsonrpc2Message() +} + +// Request is the shared interface to jsonrpc2 messages that request +// a method be invoked. +// +// The request types are a closed set of *Call and *Notification. +type Request interface { + Message + + // Method is a string containing the method name to invoke. + Method() string + // Params is either a struct or an array with the parameters of the method. + Params() json.RawMessage + + // jsonrpc2Request is used to make the set of request implementations closed. + jsonrpc2Request() +} + +// Call is a request that expects a response. +// +// The response will have a matching ID. +type Call struct { + // Method is a string containing the method name to invoke. + method string + // Params is either a struct or an array with the parameters of the method. + params json.RawMessage + // id of this request, used to tie the Response back to the request. + id ID +} + +// make sure a Call implements the Request, json.Marshaler and json.Unmarshaler and interfaces. +var ( + _ Request = (*Call)(nil) + _ json.Marshaler = (*Call)(nil) + _ json.Unmarshaler = (*Call)(nil) +) + +// NewCall constructs a new Call message for the supplied ID, method and +// parameters. +func NewCall(id ID, method string, params any) (*Call, error) { + p, merr := marshalInterface(params) + req := &Call{ + id: id, + method: method, + params: p, + } + return req, merr +} + +// ID returns the current call id. +func (c *Call) ID() ID { return c.id } + +// Method implements Request. +func (c *Call) Method() string { return c.method } + +// Params implements Request. +func (c *Call) Params() json.RawMessage { return c.params } + +// jsonrpc2Message implements Request. +func (Call) jsonrpc2Message() {} + +// jsonrpc2Request implements Request. +func (Call) jsonrpc2Request() {} + +// MarshalJSON implements json.Marshaler. +func (c Call) MarshalJSON() ([]byte, error) { + req := wireRequest{ + Method: c.method, + Params: &c.params, + ID: &c.id, + } + data, err := json.Marshal(req) + if err != nil { + return data, fmt.Errorf("marshaling call: %w", err) + } + + return data, nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (c *Call) UnmarshalJSON(data []byte) error { + var req wireRequest + dec := json.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&req); err != nil { + return fmt.Errorf("unmarshaling call: %w", err) + } + + c.method = req.Method + if req.Params != nil { + c.params = *req.Params + } + if req.ID != nil { + c.id = *req.ID + } + + return nil +} + +// Response is a reply to a Request. +// +// It will have the same ID as the call it is a response to. +type Response struct { + // result is the content of the response. + result json.RawMessage + // err is set only if the call failed. + err error + // ID of the request this is a response to. + id ID +} + +// make sure a Response implements the Message, json.Marshaler and json.Unmarshaler and interfaces. +var ( + _ Message = (*Response)(nil) + _ json.Marshaler = (*Response)(nil) + _ json.Unmarshaler = (*Response)(nil) +) + +// NewResponse constructs a new Response message that is a reply to the +// supplied. If err is set result may be ignored. +func NewResponse(id ID, result any, err error) (*Response, error) { + r, merr := marshalInterface(result) + resp := &Response{ + id: id, + result: r, + err: err, + } + return resp, merr +} + +// ID returns the current response id. +func (r *Response) ID() ID { return r.id } + +// Result returns the Response result. +func (r *Response) Result() json.RawMessage { return r.result } + +// Err returns the Response error. +func (r *Response) Err() error { return r.err } + +// jsonrpc2Message implements Message. +func (r *Response) jsonrpc2Message() {} + +// MarshalJSON implements json.Marshaler. +func (r Response) MarshalJSON() ([]byte, error) { + resp := &wireResponse{ + Error: toError(r.err), + ID: &r.id, + } + if resp.Error == nil { + resp.Result = &r.result + } + + data, err := json.Marshal(resp) + if err != nil { + return data, fmt.Errorf("marshaling notification: %w", err) + } + + return data, nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (r *Response) UnmarshalJSON(data []byte) error { + var resp wireResponse + dec := json.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&resp); err != nil { + return fmt.Errorf("unmarshaling jsonrpc response: %w", err) + } + + if resp.Result != nil { + r.result = *resp.Result + } + if resp.Error != nil { + r.err = resp.Error + } + if resp.ID != nil { + r.id = *resp.ID + } + + return nil +} + +func toError(err error) *Error { + if err == nil { + // no error, the response is complete + return nil + } + + var wrapped *Error + if errors.As(err, &wrapped) { + // already a wire error, just use it + return wrapped + } + + result := &Error{Message: err.Error()} + if errors.As(err, &wrapped) { + // if we wrapped a wire error, keep the code from the wrapped error + // but the message from the outer error + result.Code = wrapped.Code + } + + return result +} + +// Notification is a request for which a response cannot occur, and as such +// it has not ID. +type Notification struct { + // Method is a string containing the method name to invoke. + method string + + params json.RawMessage +} + +// make sure a Notification implements the Request, json.Marshaler and json.Unmarshaler and interfaces. +var ( + _ Request = (*Notification)(nil) + _ json.Marshaler = (*Notification)(nil) + _ json.Unmarshaler = (*Notification)(nil) +) + +// NewNotification constructs a new Notification message for the supplied +// method and parameters. +func NewNotification(method string, params any) (*Notification, error) { + p, merr := marshalInterface(params) + notify := &Notification{ + method: method, + params: p, + } + return notify, merr +} + +// Method implements Request. +func (n *Notification) Method() string { return n.method } + +// Params implements Request. +func (n *Notification) Params() json.RawMessage { return n.params } + +// jsonrpc2Message implements Request. +func (Notification) jsonrpc2Message() {} + +// jsonrpc2Request implements Request. +func (Notification) jsonrpc2Request() {} + +// MarshalJSON implements json.Marshaler. +func (n Notification) MarshalJSON() ([]byte, error) { + req := wireRequest{ + Method: n.method, + Params: &n.params, + } + data, err := json.Marshal(req) + if err != nil { + return data, fmt.Errorf("marshaling notification: %w", err) + } + + return data, nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (n *Notification) UnmarshalJSON(data []byte) error { + var req wireRequest + dec := json.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&req); err != nil { + return fmt.Errorf("unmarshaling notification: %w", err) + } + + n.method = req.Method + if req.Params != nil { + n.params = *req.Params + } + + return nil +} + +// DecodeMessage decodes data to Message. +func DecodeMessage(data []byte) (Message, error) { + var msg combined + dec := json.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&msg); err != nil { + return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err) + } + + if msg.Method == "" { + // no method, should be a response + if msg.ID == nil { + return nil, ErrInvalidRequest + } + + resp := &Response{ + id: *msg.ID, + } + if msg.Error != nil { + resp.err = msg.Error + } + if msg.Result != nil { + resp.result = *msg.Result + } + + return resp, nil + } + + // has a method, must be a request + if msg.ID == nil { + // request with no ID is a notify + notify := &Notification{ + method: msg.Method, + } + if msg.Params != nil { + notify.params = *msg.Params + } + + return notify, nil + } + + // request with an ID, must be a call + call := &Call{ + method: msg.Method, + id: *msg.ID, + } + if msg.Params != nil { + call.params = *msg.Params + } + + return call, nil +} + +// marshalInterface marshal obj to json.RawMessage. +func marshalInterface(obj any) (json.RawMessage, error) { + data, err := json.Marshal(obj) + if err != nil { + return json.RawMessage{}, fmt.Errorf("failed to marshal json: %w", err) + } + return json.RawMessage(data), nil +} diff --git a/templ/lsp/jsonrpc2/serve.go b/templ/lsp/jsonrpc2/serve.go new file mode 100644 index 0000000..3fc28dd --- /dev/null +++ b/templ/lsp/jsonrpc2/serve.go @@ -0,0 +1,129 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "context" + "fmt" + "net" + "os" + "time" +) + +// NOTE: This file provides an experimental API for serving multiple remote +// jsonrpc2 clients over the network. For now, it is intentionally similar to +// net/http, but that may change in the future as we figure out the correct +// semantics. + +// StreamServer is used to serve incoming jsonrpc2 clients communicating over +// a newly created connection. +type StreamServer interface { + ServeStream(context.Context, Conn) error +} + +// ServerFunc is an adapter that implements the StreamServer interface +// using an ordinary function. +type ServerFunc func(context.Context, Conn) error + +// ServeStream implements StreamServer. +// +// ServeStream calls f(ctx, s). +func (f ServerFunc) ServeStream(ctx context.Context, c Conn) error { + return f(ctx, c) +} + +// HandlerServer returns a StreamServer that handles incoming streams using the +// provided handler. +func HandlerServer(h Handler) StreamServer { + return ServerFunc(func(ctx context.Context, conn Conn) error { + conn.Go(ctx, h) + <-conn.Done() + return conn.Err() + }) +} + +// ListenAndServe starts an jsonrpc2 server on the given address. +// +// If idleTimeout is non-zero, ListenAndServe exits after there are no clients for +// this duration, otherwise it exits only on error. +func ListenAndServe(ctx context.Context, network, addr string, server StreamServer, idleTimeout time.Duration) error { + ln, err := net.Listen(network, addr) + if err != nil { + return fmt.Errorf("failed to listen %s:%s: %w", network, addr, err) + } + defer ln.Close() + + if network == "unix" { + defer os.Remove(addr) + } + + return Serve(ctx, ln, server, idleTimeout) +} + +// Serve accepts incoming connections from the network, and handles them using +// the provided server. If idleTimeout is non-zero, ListenAndServe exits after +// there are no clients for this duration, otherwise it exits only on error. +func Serve(ctx context.Context, ln net.Listener, server StreamServer, idleTimeout time.Duration) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Max duration: ~290 years; surely that's long enough. + const forever = 1<<63 - 1 + if idleTimeout <= 0 { + idleTimeout = forever + } + connTimer := time.NewTimer(idleTimeout) + + newConns := make(chan net.Conn) + doneListening := make(chan error) + closedConns := make(chan error) + + go func() { + for { + nc, err := ln.Accept() + if err != nil { + select { + case doneListening <- fmt.Errorf("accept: %w", err): + case <-ctx.Done(): + } + return + } + + newConns <- nc + } + }() + + activeConns := 0 + for { + select { + case netConn := <-newConns: + activeConns++ + connTimer.Stop() + stream := NewStream(netConn) + go func() { + conn := NewConn(stream) + closedConns <- server.ServeStream(ctx, conn) + stream.Close() + }() + + case err := <-doneListening: + return err + + case <-closedConns: + // if !isClosingError(err) { + // } + + activeConns-- + if activeConns == 0 { + connTimer.Reset(idleTimeout) + } + + case <-connTimer.C: + return ErrIdleTimeout + + case <-ctx.Done(): + return ctx.Err() + } + } +} diff --git a/templ/lsp/jsonrpc2/serve_test.go b/templ/lsp/jsonrpc2/serve_test.go new file mode 100644 index 0000000..dec11d8 --- /dev/null +++ b/templ/lsp/jsonrpc2/serve_test.go @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2_test + +import ( + "context" + "errors" + "net" + "sync" + "testing" + "time" + + "github.com/a-h/templ/lsp/jsonrpc2" +) + +func TestIdleTimeout(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + ln, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + connect := func() net.Conn { + conn, err := net.DialTimeout("tcp", ln.Addr().String(), 5*time.Second) + if err != nil { + panic(err) + } + return conn + } + + server := jsonrpc2.HandlerServer(jsonrpc2.MethodNotFoundHandler) + var ( + runErr error + wg sync.WaitGroup + ) + wg.Add(1) + go func() { + defer wg.Done() + runErr = jsonrpc2.Serve(ctx, ln, server, 100*time.Millisecond) + }() + + // Exercise some connection/disconnection patterns, and then assert that when + // our timer fires, the server exits. + conn1 := connect() + conn2 := connect() + conn1.Close() + conn2.Close() + conn3 := connect() + conn3.Close() + + wg.Wait() + + if !errors.Is(runErr, jsonrpc2.ErrIdleTimeout) { + t.Errorf("run() returned error %v, want %v", runErr, jsonrpc2.ErrIdleTimeout) + } +} diff --git a/templ/lsp/jsonrpc2/stream.go b/templ/lsp/jsonrpc2/stream.go new file mode 100644 index 0000000..dc6631f --- /dev/null +++ b/templ/lsp/jsonrpc2/stream.go @@ -0,0 +1,226 @@ +// SPDX-FileCopyrightText: 2018 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "bufio" + "context" + stdjson "encoding/json" + "fmt" + "io" + "strconv" + "strings" + + "encoding/json" +) + +const ( + // HdrContentLength is the HTTP header name of the length of the content part in bytes. This header is required. + // This entity header indicates the size of the entity-body, in bytes, sent to the recipient. + // + // RFC 7230, section 3.3.2: Content-Length: + // https://tools.ietf.org/html/rfc7230#section-3.3.2 + HdrContentLength = "Content-Length" + + // HeaderContentType is the mime type of the content part. Defaults to "application/vscode-jsonrpc; charset=utf-8". + // This entity header is used to indicate the media type of the resource. + // + // RFC 7231, section 3.1.1.5: Content-Type: + // https://tools.ietf.org/html/rfc7231#section-3.1.1.5 + HdrContentType = "Content-Type" + + // HeaderContentSeparator is the header and content part separator. + HdrContentSeparator = "\r\n\r\n" +) + +// Framer wraps a network connection up into a Stream. +// +// It is responsible for the framing and encoding of messages into wire form. +// NewRawStream and NewStream are implementations of a Framer. +type Framer func(conn io.ReadWriteCloser) Stream + +// Stream abstracts the transport mechanics from the JSON RPC protocol. +// +// A Conn reads and writes messages using the stream it was provided on +// construction, and assumes that each call to Read or Write fully transfers +// a single message, or returns an error. +// +// A stream is not safe for concurrent use, it is expected it will be used by +// a single Conn in a safe manner. +type Stream interface { + // Read gets the next message from the stream. + Read(context.Context) (Message, int64, error) + + // Write sends a message to the stream. + Write(context.Context, Message) (int64, error) + + // Close closes the connection. + // Any blocked Read or Write operations will be unblocked and return errors. + Close() error +} + +type rawStream struct { + conn io.ReadWriteCloser + in *stdjson.Decoder +} + +// NewRawStream returns a Stream built on top of a io.ReadWriteCloser. +// +// The messages are sent with no wrapping, and rely on json decode consistency +// to determine message boundaries. +func NewRawStream(conn io.ReadWriteCloser) Stream { + return &rawStream{ + conn: conn, + in: stdjson.NewDecoder(conn), // TODO(zchee): why test fail using segmentio json.Decoder? + } +} + +// Read implements Stream.Read. +func (s *rawStream) Read(ctx context.Context) (Message, int64, error) { + select { + case <-ctx.Done(): + return nil, 0, ctx.Err() + default: + } + + var raw stdjson.RawMessage + if err := s.in.Decode(&raw); err != nil { + return nil, 0, fmt.Errorf("decoding raw message: %w", err) + } + + msg, err := DecodeMessage(raw) + return msg, int64(len(raw)), err +} + +// Write implements Stream.Write. +func (s *rawStream) Write(ctx context.Context, msg Message) (int64, error) { + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + } + + data, err := json.Marshal(msg) + if err != nil { + return 0, fmt.Errorf("marshaling message: %w", err) + } + + n, err := s.conn.Write(data) + if err != nil { + return 0, fmt.Errorf("write to stream: %w", err) + } + + return int64(n), nil +} + +// Close implements Stream.Close. +func (s *rawStream) Close() error { + return s.conn.Close() +} + +type stream struct { + conn io.ReadWriteCloser + in *bufio.Reader +} + +// NewStream returns a Stream built on top of a io.ReadWriteCloser. +// +// The messages are sent with HTTP content length and MIME type headers. +// This is the format used by LSP and others. +func NewStream(conn io.ReadWriteCloser) Stream { + return &stream{ + conn: conn, + in: bufio.NewReader(conn), + } +} + +// Read implements Stream.Read. +func (s *stream) Read(ctx context.Context) (Message, int64, error) { + select { + case <-ctx.Done(): + return nil, 0, ctx.Err() + default: + } + + var total int64 + var length int64 + // read the header, stop on the first empty line + for { + line, err := s.in.ReadString('\n') + total += int64(len(line)) + if err != nil { + return nil, total, fmt.Errorf("failed reading header line: %w", err) + } + + line = strings.TrimSpace(line) + // check we have a header line + if line == "" { + break + } + + colon := strings.IndexRune(line, ':') + if colon < 0 { + return nil, total, fmt.Errorf("invalid header line %q", line) + } + + name, value := line[:colon], strings.TrimSpace(line[colon+1:]) + switch name { + case HdrContentLength: + if length, err = strconv.ParseInt(value, 10, 32); err != nil { + return nil, total, fmt.Errorf("failed parsing %s: %v: %w", HdrContentLength, value, err) + } + if length <= 0 { + return nil, total, fmt.Errorf("invalid %s: %v", HdrContentLength, length) + } + default: + // ignoring unknown headers + } + } + + if length == 0 { + return nil, total, fmt.Errorf("missing %s header", HdrContentLength) + } + + data := make([]byte, length) + if _, err := io.ReadFull(s.in, data); err != nil { + return nil, total, fmt.Errorf("read full of data: %w", err) + } + + total += length + msg, err := DecodeMessage(data) + return msg, total, err +} + +// Write implements Stream.Write. +func (s *stream) Write(ctx context.Context, msg Message) (int64, error) { + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + } + + data, err := json.Marshal(msg) + if err != nil { + return 0, fmt.Errorf("marshaling message: %w", err) + } + + n, err := fmt.Fprintf(s.conn, "%s: %v%s", HdrContentLength, len(data), HdrContentSeparator) + total := int64(n) + if err != nil { + return 0, fmt.Errorf("write data to conn: %w", err) + } + + n, err = s.conn.Write(data) + total += int64(n) + if err != nil { + return 0, fmt.Errorf("write data to conn: %w", err) + } + + return total, nil +} + +// Close implements Stream.Close. +func (s *stream) Close() error { + return s.conn.Close() +} diff --git a/templ/lsp/jsonrpc2/wire.go b/templ/lsp/jsonrpc2/wire.go new file mode 100644 index 0000000..32c9ed7 --- /dev/null +++ b/templ/lsp/jsonrpc2/wire.go @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2 + +import ( + "fmt" + + "encoding/json" +) + +// Version represents a JSON-RPC version. +const Version = "2.0" + +// version is a special 0 sized struct that encodes as the jsonrpc version tag. +// +// It will fail during decode if it is not the correct version tag in the stream. +type version struct{} + +// compile time check whether the version implements a json.Marshaler and json.Unmarshaler interfaces. +var ( + _ json.Marshaler = (*version)(nil) + _ json.Unmarshaler = (*version)(nil) +) + +// MarshalJSON implements json.Marshaler. +func (version) MarshalJSON() ([]byte, error) { + return json.Marshal(Version) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (version) UnmarshalJSON(data []byte) error { + version := "" + if err := json.Unmarshal(data, &version); err != nil { + return fmt.Errorf("failed to Unmarshal: %w", err) + } + if version != Version { + return fmt.Errorf("invalid RPC version %v", version) + } + return nil +} + +// ID is a Request identifier. +// +// Only one of either the Name or Number members will be set, using the +// number form if the Name is the empty string. +type ID struct { + name string + number int32 +} + +// compile time check whether the ID implements a fmt.Formatter, json.Marshaler and json.Unmarshaler interfaces. +var ( + _ fmt.Formatter = (*ID)(nil) + _ json.Marshaler = (*ID)(nil) + _ json.Unmarshaler = (*ID)(nil) +) + +// NewNumberID returns a new number request ID. +func NewNumberID(v int32) ID { return ID{number: v} } + +// NewStringID returns a new string request ID. +func NewStringID(v string) ID { return ID{name: v} } + +// Format writes the ID to the formatter. +// +// If the rune is q the representation is non ambiguous, +// string forms are quoted, number forms are preceded by a #. +func (id ID) Format(f fmt.State, r rune) { + numF, strF := `%d`, `%s` + if r == 'q' { + numF, strF = `#%d`, `%q` + } + + switch { + case id.name != "": + fmt.Fprintf(f, strF, id.name) + default: + fmt.Fprintf(f, numF, id.number) + } +} + +// MarshalJSON implements json.Marshaler. +func (id *ID) MarshalJSON() ([]byte, error) { + if id.name != "" { + return json.Marshal(id.name) + } + return json.Marshal(id.number) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (id *ID) UnmarshalJSON(data []byte) error { + *id = ID{} + if err := json.Unmarshal(data, &id.number); err == nil { + return nil + } + return json.Unmarshal(data, &id.name) +} + +// wireRequest is sent to a server to represent a Call or Notify operaton. +type wireRequest struct { + // VersionTag is always encoded as the string "2.0" + VersionTag version `json:"jsonrpc"` + // Method is a string containing the method name to invoke. + Method string `json:"method"` + // Params is either a struct or an array with the parameters of the method. + Params *json.RawMessage `json:"params,omitempty"` + // The id of this request, used to tie the Response back to the request. + // Will be either a string or a number. If not set, the Request is a notify, + // and no response is possible. + ID *ID `json:"id,omitempty"` +} + +// wireResponse is a reply to a Request. +// +// It will always have the ID field set to tie it back to a request, and will +// have either the Result or Error fields set depending on whether it is a +// success or failure wireResponse. +type wireResponse struct { + // VersionTag is always encoded as the string "2.0" + VersionTag version `json:"jsonrpc"` + // Result is the response value, and is required on success. + Result *json.RawMessage `json:"result,omitempty"` + // Error is a structured error response if the call fails. + Error *Error `json:"error,omitempty"` + // ID must be set and is the identifier of the Request this is a response to. + ID *ID `json:"id,omitempty"` +} + +// combined has all the fields of both Request and Response. +// +// We can decode this and then work out which it is. +type combined struct { + VersionTag version `json:"jsonrpc"` + ID *ID `json:"id,omitempty"` + Method string `json:"method"` + Params *json.RawMessage `json:"params,omitempty"` + Result *json.RawMessage `json:"result,omitempty"` + Error *Error `json:"error,omitempty"` +} diff --git a/templ/lsp/jsonrpc2/wire_test.go b/templ/lsp/jsonrpc2/wire_test.go new file mode 100644 index 0000000..a830d14 --- /dev/null +++ b/templ/lsp/jsonrpc2/wire_test.go @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package jsonrpc2_test + +import ( + "bytes" + "fmt" + "reflect" + "testing" + + "encoding/json" + + "github.com/a-h/templ/lsp/jsonrpc2" +) + +var wireIDTestData = []struct { + name string + id jsonrpc2.ID + encoded []byte + plain string + quoted string +}{ + { + name: `empty`, + encoded: []byte(`0`), + plain: `0`, + quoted: `#0`, + }, { + name: `number`, + id: jsonrpc2.NewNumberID(43), + encoded: []byte(`43`), + plain: `43`, + quoted: `#43`, + }, { + name: `string`, + id: jsonrpc2.NewStringID("life"), + encoded: []byte(`"life"`), + plain: `life`, + quoted: `"life"`, + }, +} + +func TestIDFormat(t *testing.T) { + t.Parallel() + + for _, tt := range wireIDTestData { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := fmt.Sprint(tt.id); got != tt.plain { + t.Errorf("got %s expected %s", got, tt.plain) + } + if got := fmt.Sprintf("%q", tt.id); got != tt.quoted { + t.Errorf("got %s want %s", got, tt.quoted) + } + }) + } +} + +func TestIDEncode(t *testing.T) { + t.Parallel() + + for _, tt := range wireIDTestData { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + data, err := json.Marshal(&tt.id) + if err != nil { + t.Fatal(err) + } + checkJSON(t, data, tt.encoded) + }) + } +} + +func TestIDDecode(t *testing.T) { + t.Parallel() + + for _, tt := range wireIDTestData { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got *jsonrpc2.ID + dec := json.NewDecoder(bytes.NewReader(tt.encoded)) + if err := dec.Decode(&got); err != nil { + t.Fatal(err) + } + + if reflect.ValueOf(&got).IsZero() { + t.Fatalf("got nil want %s", tt.id) + } + + if *got != tt.id { + t.Fatalf("got %s want %s", got, tt.id) + } + }) + } +} + +func TestErrorEncode(t *testing.T) { + t.Parallel() + + b, err := json.Marshal(jsonrpc2.NewError(0, "")) + if err != nil { + t.Fatal(err) + } + + checkJSON(t, b, []byte(`{ + "code": 0, + "message": "" + }`)) +} + +func TestErrorResponse(t *testing.T) { + t.Parallel() + + // originally reported in #39719, this checks that result is not present if + // it is an error response + r, _ := jsonrpc2.NewResponse(jsonrpc2.NewNumberID(3), nil, fmt.Errorf("computing fix edits")) + data, err := json.Marshal(r) + if err != nil { + t.Fatal(err) + } + + checkJSON(t, data, []byte(`{ + "jsonrpc":"2.0", + "error":{ + "code":0, + "message":"computing fix edits" + }, + "id":3 + }`)) +} + +func checkJSON(t *testing.T, got, want []byte) { + t.Helper() + + // compare the compact form, to allow for formatting differences + g := &bytes.Buffer{} + if err := json.Compact(g, got); err != nil { + t.Fatal(err) + } + + w := &bytes.Buffer{} + if err := json.Compact(w, want); err != nil { + t.Fatal(err) + } + + if g.String() != w.String() { + t.Fatalf("Got:\n%s\nWant:\n%s", g, w) + } +} diff --git a/templ/lsp/protocol/base.go b/templ/lsp/protocol/base.go new file mode 100644 index 0000000..16268f6 --- /dev/null +++ b/templ/lsp/protocol/base.go @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "encoding/json" + "fmt" +) + +// CancelParams params of cancelRequest. +type CancelParams struct { + // ID is the request id to cancel. + ID any `json:"id"` // int32 | string +} + +// ProgressParams params of Progress netification. +// +// @since 3.15.0. +type ProgressParams struct { + // Token is the progress token provided by the client or server. + Token ProgressToken `json:"token"` + + // Value is the progress data. + Value any `json:"value"` +} + +// ProgressToken is the progress token provided by the client or server. +// +// @since 3.15.0. +type ProgressToken struct { + name string + number int32 +} + +// compile time check whether the ProgressToken implements a fmt.Formatter, fmt.Stringer, json.Marshaler and json.Unmarshaler interfaces. +var ( + _ fmt.Formatter = (*ProgressToken)(nil) + _ fmt.Stringer = (*ProgressToken)(nil) + _ json.Marshaler = (*ProgressToken)(nil) + _ json.Unmarshaler = (*ProgressToken)(nil) +) + +// NewProgressToken returns a new ProgressToken. +func NewProgressToken(s string) *ProgressToken { + return &ProgressToken{name: s} +} + +// NewNumberProgressToken returns a new number ProgressToken. +func NewNumberProgressToken(n int32) *ProgressToken { + return &ProgressToken{number: n} +} + +// Format writes the ProgressToken to the formatter. +// +// If the rune is q the representation is non ambiguous, +// string forms are quoted. +func (v ProgressToken) Format(f fmt.State, r rune) { + const numF = `%d` + strF := `%s` + if r == 'q' { + strF = `%q` + } + + switch { + case v.name != "": + fmt.Fprintf(f, strF, v.name) + default: + fmt.Fprintf(f, numF, v.number) + } +} + +// String returns a string representation of the ProgressToken. +func (v ProgressToken) String() string { + return fmt.Sprint(v) +} + +// MarshalJSON implements json.Marshaler. +func (v *ProgressToken) MarshalJSON() ([]byte, error) { + if v.name != "" { + return json.Marshal(v.name) + } + + return json.Marshal(v.number) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (v *ProgressToken) UnmarshalJSON(data []byte) error { + *v = ProgressToken{} + if err := json.Unmarshal(data, &v.number); err == nil { + return nil + } + + return json.Unmarshal(data, &v.name) +} diff --git a/templ/lsp/protocol/base_test.go b/templ/lsp/protocol/base_test.go new file mode 100644 index 0000000..0cf1e32 --- /dev/null +++ b/templ/lsp/protocol/base_test.go @@ -0,0 +1,186 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "reflect" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +func TestCancelParams(t *testing.T) { + t.Parallel() + + const want = `{"id":"testID"}` + wantType := CancelParams{ + ID: "testID", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CancelParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CancelParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CancelParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestProgressParams(t *testing.T) { + t.Parallel() + + const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + const want = `{"token":"` + wantWorkDoneToken + `","value":"testValue"}` + + token := NewProgressToken(wantWorkDoneToken) + wantType := ProgressParams{ + Token: *token, + Value: "testValue", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ProgressParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ProgressParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ProgressParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(ProgressParams{}, "Token")); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if token := got.Token; !reflect.ValueOf(token).IsZero() { + if diff := cmp.Diff(fmt.Sprint(token), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} diff --git a/templ/lsp/protocol/basic.go b/templ/lsp/protocol/basic.go new file mode 100644 index 0000000..0830fa7 --- /dev/null +++ b/templ/lsp/protocol/basic.go @@ -0,0 +1,705 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "github.com/a-h/templ/lsp/uri" +) + +// DocumentURI represents the URI of a document. +// +// Many of the interfaces contain fields that correspond to the URI of a document. +// For clarity, the type of such a field is declared as a DocumentURI. +// Over the wire, it will still be transferred as a string, but this guarantees +// that the contents of that string can be parsed as a valid URI. +type DocumentURI = uri.URI + +// URI a tagging interface for normal non document URIs. +// +// @since 3.16.0. +type URI = uri.URI + +// EOL denotes represents the character offset. +var EOL = []string{"\n", "\r\n", "\r"} + +// Position represents a text document expressed as zero-based line and zero-based character offset. +// +// The offsets are based on a UTF-16 string representation. +// So a string of the form "a𐐀b" the character offset of the character "a" is 0, +// the character offset of "𐐀" is 1 and the character offset of "b" is 3 since 𐐀 is represented using two code +// units in UTF-16. +// +// Positions are line end character agnostic. So you can not specify a position that +// denotes "\r|\n" or "\n|" where "|" represents the character offset. +// +// Position is between two characters like an "insert" cursor in a editor. +// Special values like for example "-1" to denote the end of a line are not supported. +type Position struct { + // Line position in a document (zero-based). + // + // If a line number is greater than the number of lines in a document, it defaults back to the number of lines in + // the document. + // If a line number is negative, it defaults to 0. + Line uint32 `json:"line"` + + // Character offset on a line in a document (zero-based). + // + // Assuming that the line is represented as a string, the Character value represents the gap between the + // "character" and "character + 1". + // + // If the character value is greater than the line length it defaults back to the line length. + // If a line number is negative, it defaults to 0. + Character uint32 `json:"character"` +} + +// Range represents a text document expressed as (zero-based) start and end positions. +// +// A range is comparable to a selection in an editor. Therefore the end position is exclusive. +// If you want to specify a range that contains a line including the line ending character(s) then use an end position +// denoting the start of the next line. +type Range struct { + // Start is the range's start position. + Start Position `json:"start"` + + // End is the range's end position. + End Position `json:"end"` +} + +// Location represents a location inside a resource, such as a line inside a text file. +type Location struct { + URI DocumentURI `json:"uri"` + Range Range `json:"range"` +} + +// LocationLink represents a link between a source and a target location. +type LocationLink struct { + // OriginSelectionRange span of the origin of this link. + // + // Used as the underlined span for mouse interaction. Defaults to the word range at the mouse position. + OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` + + // TargetURI is the target resource identifier of this link. + TargetURI DocumentURI `json:"targetUri"` + + // TargetRange is the full target range of this link. + // + // If the target for example is a symbol then target range is the range enclosing this symbol not including + // leading/trailing whitespace but everything else like comments. + // + // This information is typically used to highlight the range in the editor. + TargetRange Range `json:"targetRange"` + + // TargetSelectionRange is the range that should be selected and revealed when this link is being followed, + // e.g the name of a function. + // + // Must be contained by the the TargetRange. See also DocumentSymbol#range + TargetSelectionRange Range `json:"targetSelectionRange"` +} + +// Command represents a reference to a command. Provides a title which will be used to represent a command in the UI. +// +// Commands are identified by a string identifier. +// The recommended way to handle commands is to implement their execution on the server side if the client and +// server provides the corresponding capabilities. +// +// Alternatively the tool extension code could handle the command. The protocol currently doesn't specify +// a set of well-known commands. +type Command struct { + // Title of the command, like `save`. + Title string `json:"title"` + + // Command is the identifier of the actual command handler. + Command string `json:"command"` + + // Arguments that the command handler should be invoked with. + Arguments []any `json:"arguments,omitempty"` +} + +// TextEdit is a textual edit applicable to a text document. +type TextEdit struct { + // Range is the range of the text document to be manipulated. + // + // To insert text into a document create a range where start == end. + Range Range `json:"range"` + + // NewText is the string to be inserted. For delete operations use an + // empty string. + NewText string `json:"newText"` +} + +// ChangeAnnotation is the additional information that describes document changes. +// +// @since 3.16.0. +type ChangeAnnotation struct { + // Label a human-readable string describing the actual change. + // The string is rendered prominent in the user interface. + Label string `json:"label"` + + // NeedsConfirmation is a flag which indicates that user confirmation is needed + // before applying the change. + NeedsConfirmation bool `json:"needsConfirmation,omitempty"` + + // Description is a human-readable string which is rendered less prominent in + // the user interface. + Description string `json:"description,omitempty"` +} + +// ChangeAnnotationIdentifier an identifier referring to a change annotation managed by a workspace +// edit. +// +// @since 3.16.0. +type ChangeAnnotationIdentifier string + +// AnnotatedTextEdit is a special text edit with an additional change annotation. +// +// @since 3.16.0. +type AnnotatedTextEdit struct { + TextEdit + + // AnnotationID is the actual annotation identifier. + AnnotationID ChangeAnnotationIdentifier `json:"annotationId"` +} + +// TextDocumentEdit describes textual changes on a single text document. +// +// The TextDocument is referred to as a OptionalVersionedTextDocumentIdentifier to allow clients to check the +// text document version before an edit is applied. +// +// TextDocumentEdit describes all changes on a version "Si" and after they are applied move the document to +// version "Si+1". +// So the creator of a TextDocumentEdit doesn't need to sort the array or do any kind of ordering. However the +// edits must be non overlapping. +type TextDocumentEdit struct { + // TextDocument is the text document to change. + TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"` + + // Edits is the edits to be applied. + // + // @since 3.16.0 - support for AnnotatedTextEdit. + // This is guarded by the client capability Workspace.WorkspaceEdit.ChangeAnnotationSupport. + Edits []TextEdit `json:"edits"` // []TextEdit | []AnnotatedTextEdit +} + +// ResourceOperationKind is the file event type. +type ResourceOperationKind string + +const ( + // CreateResourceOperation supports creating new files and folders. + CreateResourceOperation ResourceOperationKind = "create" + + // RenameResourceOperation supports renaming existing files and folders. + RenameResourceOperation ResourceOperationKind = "rename" + + // DeleteResourceOperation supports deleting existing files and folders. + DeleteResourceOperation ResourceOperationKind = "delete" +) + +// CreateFileOptions represents an options to create a file. +type CreateFileOptions struct { + // Overwrite existing file. Overwrite wins over `ignoreIfExists`. + Overwrite bool `json:"overwrite,omitempty"` + + // IgnoreIfExists ignore if exists. + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +// CreateFile represents a create file operation. +type CreateFile struct { + // Kind a create. + Kind ResourceOperationKind `json:"kind"` // should be `create` + + // URI is the resource to create. + URI DocumentURI `json:"uri"` + + // Options additional options. + Options *CreateFileOptions `json:"options,omitempty"` + + // AnnotationID an optional annotation identifier describing the operation. + // + // @since 3.16.0. + AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"` +} + +// RenameFileOptions represents a rename file options. +type RenameFileOptions struct { + // Overwrite target if existing. Overwrite wins over `ignoreIfExists`. + Overwrite bool `json:"overwrite,omitempty"` + + // IgnoreIfExists ignores if target exists. + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +// RenameFile represents a rename file operation. +type RenameFile struct { + // Kind a rename. + Kind ResourceOperationKind `json:"kind"` // should be `rename` + + // OldURI is the old (existing) location. + OldURI DocumentURI `json:"oldUri"` + + // NewURI is the new location. + NewURI DocumentURI `json:"newUri"` + + // Options rename options. + Options *RenameFileOptions `json:"options,omitempty"` + + // AnnotationID an optional annotation identifier describing the operation. + // + // @since 3.16.0. + AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"` +} + +// DeleteFileOptions represents a delete file options. +type DeleteFileOptions struct { + // Recursive delete the content recursively if a folder is denoted. + Recursive bool `json:"recursive,omitempty"` + + // IgnoreIfNotExists ignore the operation if the file doesn't exist. + IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"` +} + +// DeleteFile represents a delete file operation. +type DeleteFile struct { + // Kind is a delete. + Kind ResourceOperationKind `json:"kind"` // should be `delete` + + // URI is the file to delete. + URI DocumentURI `json:"uri"` + + // Options delete options. + Options *DeleteFileOptions `json:"options,omitempty"` + + // AnnotationID an optional annotation identifier describing the operation. + // + // @since 3.16.0. + AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"` +} + +// WorkspaceEdit represent a changes to many resources managed in the workspace. +// +// The edit should either provide changes or documentChanges. +// If the client can handle versioned document edits and if documentChanges are present, the latter are preferred over +// changes. +type WorkspaceEdit struct { + // Changes holds changes to existing resources. + Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"` + + // DocumentChanges depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + // are either an array of `TextDocumentEdit`s to express changes to n different text documents + // where each text document edit addresses a specific version of a text document. Or it can contain + // above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + // + // Whether a client supports versioned document edits is expressed via + // `workspace.workspaceEdit.documentChanges` client capability. + // + // If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + // only plain `TextEdit`s using the `changes` property are supported. + DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"` + + // ChangeAnnotations is a map of change annotations that can be referenced in + // "AnnotatedTextEdit"s or create, rename and delete file / folder + // operations. + // + // Whether clients honor this property depends on the client capability + // "workspace.changeAnnotationSupport". + // + // @since 3.16.0. + ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"` +} + +// TextDocumentIdentifier indicates the using a URI. On the protocol level, URIs are passed as strings. +type TextDocumentIdentifier struct { + // URI is the text document's URI. + URI DocumentURI `json:"uri"` +} + +// TextDocumentItem represent an item to transfer a text document from the client to the server. +type TextDocumentItem struct { + // URI is the text document's URI. + URI DocumentURI `json:"uri"` + + // LanguageID is the text document's language identifier. + LanguageID LanguageIdentifier `json:"languageId"` + + // Version is the version number of this document (it will increase after each + // change, including undo/redo). + Version int32 `json:"version"` + + // Text is the content of the opened text document. + Text string `json:"text"` +} + +// LanguageIdentifier represent a text document's language identifier. +type LanguageIdentifier string + +const ( + // ABAPLanguage ABAP Language. + ABAPLanguage LanguageIdentifier = "abap" + + // BatLanguage Windows Bat Language. + BatLanguage LanguageIdentifier = "bat" + + // BibtexLanguage BibTeX Language. + BibtexLanguage LanguageIdentifier = "bibtex" + + // ClojureLanguage Clojure Language. + ClojureLanguage LanguageIdentifier = "clojure" + + // CoffeescriptLanguage CoffeeScript Language. + CoffeeScriptLanguage LanguageIdentifier = "coffeescript" + + // CLanguage C Language. + CLanguage LanguageIdentifier = "c" + + // CppLanguage C++ Language. + CppLanguage LanguageIdentifier = "cpp" + + // CsharpLanguage C# Language. + CsharpLanguage LanguageIdentifier = "csharp" + + // CSSLanguage CSS Language. + CSSLanguage LanguageIdentifier = "css" + + // DiffLanguage Diff Language. + DiffLanguage LanguageIdentifier = "diff" + + // DartLanguage Dart Language. + DartLanguage LanguageIdentifier = "dart" + + // DockerfileLanguage Dockerfile Language. + DockerfileLanguage LanguageIdentifier = "dockerfile" + + // ElixirLanguage Elixir Language. + ElixirLanguage LanguageIdentifier = "elixir" + + // ErlangLanguage Erlang Language. + ErlangLanguage LanguageIdentifier = "erlang" + + // FsharpLanguage F# Language. + FsharpLanguage LanguageIdentifier = "fsharp" + + // GitCommitLanguage Git Language. + GitCommitLanguage LanguageIdentifier = "git-commit" + + // GitRebaseLanguage Git Language. + GitRebaseLanguage LanguageIdentifier = "git-rebase" + + // GoLanguage Go Language. + GoLanguage LanguageIdentifier = "go" + + // GroovyLanguage Groovy Language. + GroovyLanguage LanguageIdentifier = "groovy" + + // HandlebarsLanguage Handlebars Language. + HandlebarsLanguage LanguageIdentifier = "handlebars" + + // HTMLLanguage HTML Language. + HTMLLanguage LanguageIdentifier = "html" + + // IniLanguage Ini Language. + IniLanguage LanguageIdentifier = "ini" + + // JavaLanguage Java Language. + JavaLanguage LanguageIdentifier = "java" + + // JavaScriptLanguage JavaScript Language. + JavaScriptLanguage LanguageIdentifier = "javascript" + + // JavaScriptReactLanguage JavaScript React Language. + JavaScriptReactLanguage LanguageIdentifier = "javascriptreact" + + // JSONLanguage JSON Language. + JSONLanguage LanguageIdentifier = "json" + + // LatexLanguage LaTeX Language. + LatexLanguage LanguageIdentifier = "latex" + + // LessLanguage Less Language. + LessLanguage LanguageIdentifier = "less" + + // LuaLanguage Lua Language. + LuaLanguage LanguageIdentifier = "lua" + + // MakefileLanguage Makefile Language. + MakefileLanguage LanguageIdentifier = "makefile" + + // MarkdownLanguage Markdown Language. + MarkdownLanguage LanguageIdentifier = "markdown" + + // ObjectiveCLanguage Objective-C Language. + ObjectiveCLanguage LanguageIdentifier = "objective-c" + + // ObjectiveCppLanguage Objective-C++ Language. + ObjectiveCppLanguage LanguageIdentifier = "objective-cpp" + + // PerlLanguage Perl Language. + PerlLanguage LanguageIdentifier = "perl" + + // Perl6Language Perl Language. + Perl6Language LanguageIdentifier = "perl6" + + // PHPLanguage PHP Language. + PHPLanguage LanguageIdentifier = "php" + + // PowershellLanguage Powershell Language. + PowershellLanguage LanguageIdentifier = "powershell" + + // JadeLanguage Pug Language. + JadeLanguage LanguageIdentifier = "jade" + + // PythonLanguage Python Language. + PythonLanguage LanguageIdentifier = "python" + + // RLanguage R Language. + RLanguage LanguageIdentifier = "r" + + // RazorLanguage Razor(cshtml) Language. + RazorLanguage LanguageIdentifier = "razor" + + // RubyLanguage Ruby Language. + RubyLanguage LanguageIdentifier = "ruby" + + // RustLanguage Rust Language. + RustLanguage LanguageIdentifier = "rust" + + // SCSSLanguage SCSS Languages syntax using curly brackets. + SCSSLanguage LanguageIdentifier = "scss" + + // SASSLanguage SCSS Languages indented syntax. + SASSLanguage LanguageIdentifier = "sass" + + // ScalaLanguage Scala Language. + ScalaLanguage LanguageIdentifier = "scala" + + // ShaderlabLanguage ShaderLab Language. + ShaderlabLanguage LanguageIdentifier = "shaderlab" + + // ShellscriptLanguage Shell Script (Bash) Language. + ShellscriptLanguage LanguageIdentifier = "shellscript" + + // SQLLanguage SQL Language. + SQLLanguage LanguageIdentifier = "sql" + + // SwiftLanguage Swift Language. + SwiftLanguage LanguageIdentifier = "swift" + + // TypeScriptLanguage TypeScript Language. + TypeScriptLanguage LanguageIdentifier = "typescript" + + // TypeScriptReactLanguage TypeScript React Language. + TypeScriptReactLanguage LanguageIdentifier = "typescriptreact" + + // TeXLanguage TeX Language. + TeXLanguage LanguageIdentifier = "tex" + + // VBLanguage Visual Basic Language. + VBLanguage LanguageIdentifier = "vb" + + // XMLLanguage XML Language. + XMLLanguage LanguageIdentifier = "xml" + + // XslLanguage XSL Language. + XslLanguage LanguageIdentifier = "xsl" + + // YamlLanguage YAML Language. + YamlLanguage LanguageIdentifier = "yaml" +) + +// languageIdentifierMap map of LanguageIdentifiers. +var languageIdentifierMap = map[string]LanguageIdentifier{ + "abap": ABAPLanguage, + "bat": BatLanguage, + "bibtex": BibtexLanguage, + "clojure": ClojureLanguage, + "coffeescript": CoffeeScriptLanguage, + "c": CLanguage, + "cpp": CppLanguage, + "csharp": CsharpLanguage, + "css": CSSLanguage, + "diff": DiffLanguage, + "dart": DartLanguage, + "dockerfile": DockerfileLanguage, + "elixir": ElixirLanguage, + "erlang": ErlangLanguage, + "fsharp": FsharpLanguage, + "git-commit": GitCommitLanguage, + "git-rebase": GitRebaseLanguage, + "go": GoLanguage, + "groovy": GroovyLanguage, + "handlebars": HandlebarsLanguage, + "html": HTMLLanguage, + "ini": IniLanguage, + "java": JavaLanguage, + "javascript": JavaScriptLanguage, + "javascriptreact": JavaScriptReactLanguage, + "json": JSONLanguage, + "latex": LatexLanguage, + "less": LessLanguage, + "lua": LuaLanguage, + "makefile": MakefileLanguage, + "markdown": MarkdownLanguage, + "objective-c": ObjectiveCLanguage, + "objective-cpp": ObjectiveCppLanguage, + "perl": PerlLanguage, + "perl6": Perl6Language, + "php": PHPLanguage, + "powershell": PowershellLanguage, + "jade": JadeLanguage, + "python": PythonLanguage, + "r": RLanguage, + "razor": RazorLanguage, + "ruby": RubyLanguage, + "rust": RustLanguage, + "scss": SCSSLanguage, + "sass": SASSLanguage, + "scala": ScalaLanguage, + "shaderlab": ShaderlabLanguage, + "shellscript": ShellscriptLanguage, + "sql": SQLLanguage, + "swift": SwiftLanguage, + "typescript": TypeScriptLanguage, + "typescriptreact": TypeScriptReactLanguage, + "tex": TeXLanguage, + "vb": VBLanguage, + "xml": XMLLanguage, + "xsl": XslLanguage, + "yaml": YamlLanguage, +} + +// ToLanguageIdentifier converts ft to LanguageIdentifier. +func ToLanguageIdentifier(ft string) LanguageIdentifier { + langID, ok := languageIdentifierMap[ft] + if ok { + return langID + } + + return LanguageIdentifier(ft) +} + +// VersionedTextDocumentIdentifier represents an identifier to denote a specific version of a text document. +// +// This information usually flows from the client to the server. +type VersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + // Version is the version number of this document. + // + // The version number of a document will increase after each change, including + // undo/redo. The number doesn't need to be consecutive. + Version int32 `json:"version"` +} + +// OptionalVersionedTextDocumentIdentifier represents an identifier which optionally denotes a specific version of +// a text document. +// +// This information usually flows from the server to the client. +// +// @since 3.16.0. +type OptionalVersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + // Version is the version number of this document. If an optional versioned text document + // identifier is sent from the server to the client and the file is not + // open in the editor (the server has not received an open notification + // before) the server can send `null` to indicate that the version is + // known and the content on disk is the master (as specified with document + // content ownership). + // + // The version number of a document will increase after each change, + // including undo/redo. The number doesn't need to be consecutive. + Version *int32 `json:"version"` // int32 | null +} + +// TextDocumentPositionParams is a parameter literal used in requests to pass a text document and a position +// inside that document. +// +// It is up to the client to decide how a selection is converted into a position when issuing a request for a text +// document. +// +// The client can for example honor or ignore the selection direction to make LSP request consistent with features +// implemented internally. +type TextDocumentPositionParams struct { + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Position is the position inside the text document. + Position Position `json:"position"` +} + +// DocumentFilter is a document filter denotes a document through properties like language, scheme or pattern. +// +// An example is a filter that applies to TypeScript files on disk. +type DocumentFilter struct { + // Language a language id, like `typescript`. + Language string `json:"language,omitempty"` + + // Scheme a URI scheme, like `file` or `untitled`. + Scheme string `json:"scheme,omitempty"` + + // Pattern a glob pattern, like `*.{ts,js}`. + // + // Glob patterns can have the following syntax: + // "*" + // "*" to match one or more characters in a path segment + // "?" + // "?" to match on one character in a path segment + // "**" + // "**" to match any number of path segments, including none + // "{}" + // "{}" to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) + // "[]" + // "[]" to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + // "[!...]" + // "[!...]" to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + Pattern string `json:"pattern,omitempty"` +} + +// DocumentSelector is a document selector is the combination of one or more document filters. +type DocumentSelector []*DocumentFilter + +// MarkupKind describes the content type that a client supports in various +// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. +// +// Please note that `MarkupKinds` must not start with a `$`. This kinds +// are reserved for internal usage. +type MarkupKind string + +const ( + // PlainText is supported as a content format. + PlainText MarkupKind = "plaintext" + + // Markdown is supported as a content format. + Markdown MarkupKind = "markdown" +) + +// MarkupContent a `MarkupContent` literal represents a string value which content is interpreted base on its +// kind flag. +// +// Currently the protocol supports `plaintext` and `markdown` as markup kinds. +// +// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. +// See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting +// +// Here is an example how such a string can be constructed using JavaScript / TypeScript: +// +// let markdown: MarkdownContent = { +// kind: MarkupKind.Markdown, +// value: [ +// '# Header', +// 'Some text', +// '```typescript', +// 'someCode();', +// '```' +// ].join('\n') +// }; +// +// NOTE: clients might sanitize the return markdown. A client could decide to +// remove HTML from the markdown to avoid script execution. +type MarkupContent struct { + // Kind is the type of the Markup + Kind MarkupKind `json:"kind"` + + // Value is the content itself + Value string `json:"value"` +} diff --git a/templ/lsp/protocol/basic_test.go b/templ/lsp/protocol/basic_test.go new file mode 100644 index 0000000..b3925a7 --- /dev/null +++ b/templ/lsp/protocol/basic_test.go @@ -0,0 +1,3213 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + + "github.com/a-h/templ/lsp/uri" +) + +func TestPosition(t *testing.T) { + t.Parallel() + + const ( + want = `{"line":25,"character":1}` + wantInvalid = `{"line":2,"character":0}` + ) + wantType := Position{ + Line: 25, + Character: 1, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Position + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Position + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Position + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRange(t *testing.T) { + t.Parallel() + + const ( + want = `{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}` + wantInvalid = `{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}` + ) + wantType := Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Range + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Range + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Range + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestLocation(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///Users/gopher/go/src/github.com/a-h/templ/lsp/protocol/basic_test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"uri":"file:///Users/gopher/go/src/github.com/a-h/templ/lsp/protocol/basic_test.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}}` + ) + wantType := Location{ + URI: uri.File("/Users/gopher/go/src/github.com/a-h/templ/lsp/protocol/basic_test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Location + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Location + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Location + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestLocationLink(t *testing.T) { + t.Parallel() + + const ( + want = `{"originSelectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"targetUri":"file:///path/to/test.go","targetRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"targetSelectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantNil = `{"targetUri":"file:///path/to/test.go","targetRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"targetSelectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"originSelectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"targetUri":"file:///path/to/test.go","targetRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"targetSelectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}}` + ) + wantType := LocationLink{ + OriginSelectionRange: &Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + TargetURI: uri.File("/path/to/test.go"), + TargetRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + TargetSelectionRange: Range{ + Start: Position{ + Line: 25, Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + wantTypeNil := LocationLink{ + TargetURI: uri.File("/path/to/test.go"), + TargetRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + TargetSelectionRange: Range{ + Start: Position{ + Line: 25, Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field LocationLink + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOriginSelectionRange", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want LocationLink + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOriginSelectionRange", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got LocationLink + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeDescription(t *testing.T) { + t.Parallel() + + const ( + want = `{"href":"file:///path/to/test.go"}` + wantInvalid = `{"href":"file:///path/to/invalid.go"}` + ) + wantType := CodeDescription{ + Href: uri.File("/path/to/test.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CodeDescription + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CodeDescription + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeDescription + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCommand(t *testing.T) { + t.Parallel() + + const ( + want = `{"title":"exec echo","command":"echo","arguments":["hello"]}` + wantNilArguments = `{"title":"exec echo","command":"echo"}` + wantInvalid = `{"title":"exec echo","command":"true","arguments":["hello"]}` + ) + wantType := Command{ + Title: "exec echo", + Command: "echo", + Arguments: []any{"hello"}, + } + wantTypeNilArguments := Command{ + Title: "exec echo", + Command: "echo", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field Command + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilArguments", + field: wantTypeNilArguments, + want: wantNilArguments, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want Command + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilArguments", + field: wantNilArguments, + want: wantTypeNilArguments, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Command + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestChangeAnnotation(t *testing.T) { + t.Parallel() + + const ( + want = `{"label":"testLabel","needsConfirmation":true,"description":"testDescription"}` + wantNilAll = `{"label":"testLabel"}` + wantInvalid = `{"label":"invalidLabel","needsConfirmation":false,"description":"invalidDescription"}` + ) + wantType := ChangeAnnotation{ + Label: "testLabel", + NeedsConfirmation: true, + Description: "testDescription", + } + wantTypeNilAll := ChangeAnnotation{ + Label: "testLabel", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ChangeAnnotation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilArguments", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ChangeAnnotation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilArguments", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ChangeAnnotation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestAnnotatedTextEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar","annotationId":"testAnnotationIdentifier"}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar","annotationId":"invalidAnnotationIdentifier"}` + ) + wantType := AnnotatedTextEdit{ + TextEdit: TextEdit{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + AnnotationID: ChangeAnnotationIdentifier("testAnnotationIdentifier"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field AnnotatedTextEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want AnnotatedTextEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got AnnotatedTextEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}` + ) + wantType := TextEdit{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + } + wantInvalidType := TextEdit{ + Range: Range{ + Start: Position{ + Line: 2, + Character: 1, + }, + End: Position{ + Line: 3, + Character: 2, + }, + }, + NewText: "foo bar", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: TextEdit{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: want, + want: wantInvalidType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go","version":10},"edits":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]}` + ) + wantType := TextDocumentEdit{ + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: "file:///path/to/basic.go", + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + } + wantInvalidType := TextDocumentEdit{ + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: "file:///path/to/basic.go", + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 2, + Character: 1, + }, + End: Position{ + Line: 3, + Character: 2, + }, + }, + NewText: "foo bar", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: want, + want: wantInvalidType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCreateFileOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"overwrite":true,"ignoreIfExists":true}` + wantNilIgnoreIfExists = `{"overwrite":true}` + wantNilOverwrite = `{"ignoreIfExists":true}` + wantValidNilAll = `{}` + wantInvalid = `{"overwrite":false,"ignoreIfExists":false}` + ) + wantType := CreateFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + } + wantTypeNilOverwrite := CreateFileOptions{ + IgnoreIfExists: true, + } + wantTypeNilIgnoreIfExists := CreateFileOptions{ + Overwrite: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CreateFileOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOverwrite", + field: wantTypeNilIgnoreIfExists, + want: wantNilIgnoreIfExists, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilIgnoreIfExists", + field: wantTypeNilOverwrite, + want: wantNilOverwrite, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: CreateFileOptions{}, + want: wantValidNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CreateFileOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: `{"overwrite":true,"ignoreIfExists":true}`, + want: CreateFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOverwrite", + field: `{"ignoreIfExists":true}`, + want: CreateFileOptions{ + IgnoreIfExists: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilIgnoreIfExists", + field: `{"overwrite":true}`, + want: CreateFileOptions{ + Overwrite: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: `{}`, + want: CreateFileOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: `{"overwrite":true,"ignoreIfExists":true}`, + want: CreateFileOptions{ + Overwrite: false, + IgnoreIfExists: false, + }, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CreateFileOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCreateFile(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"create","uri":"file:///path/to/basic.go","options":{"overwrite":true,"ignoreIfExists":true},"annotationId":"testAnnotationIdentifier"}` + wantNilOptions = `{"kind":"create","uri":"file:///path/to/basic.go"}` + wantInvalid = `{"kind":"create","uri":"file:///path/to/basic_gen.go","options":{"overwrite":false,"ignoreIfExists":false},"annotationId":"invalidAnnotationIdentifier"}` + ) + wantType := CreateFile{ + Kind: "create", + URI: uri.File("/path/to/basic.go"), + Options: &CreateFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + }, + AnnotationID: ChangeAnnotationIdentifier("testAnnotationIdentifier"), + } + wantTypeNilOptions := CreateFile{ + Kind: "create", + URI: uri.File("/path/to/basic.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CreateFile + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantTypeNilOptions, + want: wantNilOptions, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CreateFile + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantNilOptions, + want: wantTypeNilOptions, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CreateFile + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameFileOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"overwrite":true,"ignoreIfExists":true}` + wantNilOverwrite = `{"ignoreIfExists":true}` + wantNilIgnoreIfExists = `{"overwrite":true}` + wantNilAll = `{}` + wantInvalid = `{"overwrite":false,"ignoreIfExists":false}` + ) + wantType := RenameFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + } + wantTypeNilOverwrite := RenameFileOptions{ + IgnoreIfExists: true, + } + wantTypeNilIgnoreIfExists := RenameFileOptions{ + Overwrite: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field RenameFileOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOverwrite", + field: wantTypeNilOverwrite, + want: wantNilOverwrite, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilIgnoreIfExists", + field: wantTypeNilIgnoreIfExists, + want: wantNilIgnoreIfExists, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: RenameFileOptions{}, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want RenameFileOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: `{"overwrite":true,"ignoreIfExists":true}`, + want: RenameFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOverwrite", + field: `{"ignoreIfExists":true}`, + want: RenameFileOptions{ + IgnoreIfExists: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilIgnoreIfExists", + field: `{"overwrite":true}`, + want: RenameFileOptions{ + Overwrite: true, + }, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: `{}`, + want: RenameFileOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: `{"overwrite":true,"ignoreIfExists":true}`, + want: RenameFileOptions{ + Overwrite: false, + IgnoreIfExists: false, + }, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameFileOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameFile(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"rename","oldUri":"file:///path/to/old.go","newUri":"file:///path/to/new.go","options":{"overwrite":true,"ignoreIfExists":true},"annotationId":"testAnnotationIdentifier"}` + wantNilOptions = `{"kind":"rename","oldUri":"file:///path/to/old.go","newUri":"file:///path/to/new.go"}` + wantInvalid = `{"kind":"rename","oldUri":"file:///path/to/old2.go","newUri":"file:///path/to/new2.go","options":{"overwrite":false,"ignoreIfExists":false},"annotationId":"invalidAnnotationIdentifier"}` + ) + wantType := RenameFile{ + Kind: "rename", + OldURI: uri.File("/path/to/old.go"), + NewURI: uri.File("/path/to/new.go"), + Options: &RenameFileOptions{ + Overwrite: true, + IgnoreIfExists: true, + }, + AnnotationID: ChangeAnnotationIdentifier("testAnnotationIdentifier"), + } + wantTypeNilOptions := RenameFile{ + Kind: "rename", + OldURI: uri.File("/path/to/old.go"), + NewURI: uri.File("/path/to/new.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field RenameFile + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantTypeNilOptions, + want: wantNilOptions, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want RenameFile + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantNilOptions, + want: wantTypeNilOptions, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameFile + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeleteFileOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"recursive":true,"ignoreIfNotExists":true}` + wantNilRecursive = `{"ignoreIfNotExists":true}` + wantNiIgnoreIfNotExists = `{"recursive":true}` + wantNilAll = `{}` + wantInvalid = `{"recursive":false,"ignoreIfNotExists":false}` + ) + wantType := DeleteFileOptions{ + Recursive: true, + IgnoreIfNotExists: true, + } + wantTypeNilRecursive := DeleteFileOptions{ + IgnoreIfNotExists: true, + } + wantTypeNiIgnoreIfNotExists := DeleteFileOptions{ + Recursive: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeleteFileOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilRecursive", + field: wantTypeNilRecursive, + want: wantNilRecursive, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNiIgnoreIfNotExists", + field: wantTypeNiIgnoreIfNotExists, + want: wantNiIgnoreIfNotExists, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DeleteFileOptions{}, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeleteFileOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilRecursive", + field: wantNilRecursive, + want: wantTypeNilRecursive, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilIgnoreIfNotExists", + field: wantNiIgnoreIfNotExists, + want: wantTypeNiIgnoreIfNotExists, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: DeleteFileOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeleteFileOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeleteFile(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"delete","uri":"file:///path/to/delete.go","options":{"recursive":true,"ignoreIfNotExists":true},"annotationId":"testAnnotationIdentifier"}` + wantNilOptions = `{"kind":"delete","uri":"file:///path/to/delete.go"}` + wantInvalid = `{"kind":"delete","uri":"file:///path/to/delete2.go","options":{"recursive":false,"ignoreIfNotExists":false},"annotationId":"invalidAnnotationIdentifier"}` + ) + wantType := DeleteFile{ + Kind: "delete", + URI: uri.File("/path/to/delete.go"), + Options: &DeleteFileOptions{ + Recursive: true, + IgnoreIfNotExists: true, + }, + AnnotationID: ChangeAnnotationIdentifier("testAnnotationIdentifier"), + } + wantTypeNilOptions := DeleteFile{ + Kind: "delete", + URI: uri.File("/path/to/delete.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeleteFile + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantTypeNilOptions, + want: wantNilOptions, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeleteFile + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilOptions", + field: wantNilOptions, + want: wantTypeNilOptions, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeleteFile + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkspaceEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"changes":{"file:///path/to/basic.go":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}],"changeAnnotations":{"testAnnotationIdentifier":{"label":"testLabel","needsConfirmation":true,"description":"testDescription"}}}` + wantNilChanges = `{"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}]}` + wantNilDocumentChanges = `{"changes":{"file:///path/to/basic.go":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}}` + wantInvalid = `{"changes":{"file:///path/to/basic_gen.go":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic_gen.go","version":10},"edits":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]}]}` + ) + wantType := WorkspaceEdit{ + Changes: map[uri.URI][]TextEdit{ + uri.File("/path/to/basic.go"): { + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + DocumentChanges: []TextDocumentEdit{ + { + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + }, + ChangeAnnotations: map[ChangeAnnotationIdentifier]ChangeAnnotation{ + ChangeAnnotationIdentifier("testAnnotationIdentifier"): { + Label: "testLabel", + NeedsConfirmation: true, + Description: "testDescription", + }, + }, + } + wantTypeNilChanges := WorkspaceEdit{ + DocumentChanges: []TextDocumentEdit{ + { + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + }, + } + wantTypeNilDocumentChanges := WorkspaceEdit{ + Changes: map[uri.URI][]TextEdit{ + uri.File("/path/to/basic.go"): { + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field WorkspaceEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilChanges", + field: wantTypeNilChanges, + want: wantNilChanges, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilDocumentChanges", + field: wantTypeNilDocumentChanges, + want: wantNilDocumentChanges, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want WorkspaceEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilChanges", + field: wantNilChanges, + want: wantTypeNilChanges, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilDocumentChanges", + field: wantNilDocumentChanges, + want: wantTypeNilDocumentChanges, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentIdentifier(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/basic.go"}` + wantInvalid = `{"uri":"file:///path/to/unknown.go"}` + wantInvalidEmpty = `{}` + ) + wantType := TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentIdentifier + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + { + name: "InvalidEmpty", + field: TextDocumentIdentifier{}, + want: wantInvalidEmpty, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentIdentifier + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentIdentifier + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentItem(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/basic.go","languageId":"go","version":10,"text":"Go Language"}` + wantInvalid = `{"uri":"file:///path/to/basic_gen.go","languageId":"cpp","version":10,"text":"C++ Language"}` + ) + wantType := TextDocumentItem{ + URI: uri.File("/path/to/basic.go"), + LanguageID: GoLanguage, + Version: int32(10), + Text: "Go Language", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentItem + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentItem + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentItem + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestToLanguageIdentifier(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + ft string + want LanguageIdentifier + }{ + { + name: "Go", + ft: "go", + want: GoLanguage, + }, + { + name: "C", + ft: "c", + want: CLanguage, + }, + { + name: "lsif", + ft: "lsif", + want: LanguageIdentifier("lsif"), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := ToLanguageIdentifier(tt.ft); got != tt.want { + t.Errorf("ToLanguageIdentifier(%v) = %v, want %v", tt.ft, tt.want, got) + } + }) + } +} + +func TestVersionedTextDocumentIdentifier(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/basic.go","version":10}` + wantZeroVersion = `{"uri":"file:///path/to/basic.go","version":0}` + wantInvalid = `{"uri":"file:///path/to/basic_gen.go","version":50}` + ) + wantType := VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: int32(10), + } + wantTypeNullVersion := VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field VersionedTextDocumentIdentifier + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNullVersion", + field: wantTypeNullVersion, + want: wantZeroVersion, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want VersionedTextDocumentIdentifier + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNullVersion", + field: wantZeroVersion, + want: wantTypeNullVersion, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got VersionedTextDocumentIdentifier + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestOptionalVersionedTextDocumentIdentifier(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/basic.go","version":10}` + wantNullVersion = `{"uri":"file:///path/to/basic.go","version":null}` + wantInvalid = `{"uri":"file:///path/to/basic_gen.go","version":50}` + ) + wantType := OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: NewVersion(10), + } + wantTypeNullVersion := OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field OptionalVersionedTextDocumentIdentifier + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNullVersion", + field: wantTypeNullVersion, + want: wantNullVersion, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want OptionalVersionedTextDocumentIdentifier + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNullVersion", + field: wantNullVersion, + want: wantTypeNullVersion, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got OptionalVersionedTextDocumentIdentifier + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentPositionParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1}}` + ) + wantType := TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentPositionParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentPositionParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentPositionParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentFilter(t *testing.T) { + t.Parallel() + + const ( + want = `{"language":"go","scheme":"file","pattern":"*"}` + wantNilLanguage = `{"scheme":"file","pattern":"*"}` + wantNilScheme = `{"language":"go","pattern":"*"}` + wantNilPattern = `{"language":"go","scheme":"file"}` + wantNilAll = `{}` + wantInvalid = `{"language":"typescript","scheme":"file","pattern":"?"}` + ) + wantType := DocumentFilter{ + Language: "go", + Scheme: "file", + Pattern: "*", + } + wantTypeNilLanguage := DocumentFilter{ + Scheme: "file", + Pattern: "*", + } + wantTypeNilScheme := DocumentFilter{ + Language: "go", + Pattern: "*", + } + wantTypeNilPattern := DocumentFilter{ + Language: "go", + Scheme: "file", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentFilter + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilLanguage", + field: wantTypeNilLanguage, + want: wantNilLanguage, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilScheme", + field: wantTypeNilScheme, + want: wantNilScheme, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilPattern", + field: wantTypeNilPattern, + want: wantNilPattern, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentFilter{}, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentFilter + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilLanguage", + field: wantNilLanguage, + want: wantTypeNilLanguage, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilScheme", + field: wantNilScheme, + want: wantTypeNilScheme, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilPattern", + field: wantNilPattern, + want: wantTypeNilPattern, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: DocumentFilter{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentFilter + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentSelector(t *testing.T) { + t.Parallel() + + const ( + want = `[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]` + wantInvalid = `[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}]` + ) + wantType := DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentSelector + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentSelector + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentSelector + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestMarkupContent(t *testing.T) { + t.Parallel() + + const ( + want = "{\"kind\":\"markdown\",\"value\":\"# Header\\nSome text\\n```typescript\\nsomeCode();\\n'```\\n\"}" + wantInvalid = "{\"kind\":\"plaintext\",\"value\":\"Header\\nSome text\\ntypescript\\nsomeCode();\\n\"}" + ) + wantType := MarkupContent{ + Kind: Markdown, + Value: "# Header\nSome text\n```typescript\nsomeCode();\n'```\n", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field MarkupContent + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want MarkupContent + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got MarkupContent + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/callhierarchy.go b/templ/lsp/protocol/callhierarchy.go new file mode 100644 index 0000000..69a4d13 --- /dev/null +++ b/templ/lsp/protocol/callhierarchy.go @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// CallHierarchy capabilities specific to the "textDocument/callHierarchy". +// +// @since 3.16.0. +type CallHierarchy struct { + // DynamicRegistration whether implementation supports dynamic registration. + // + // If this is set to "true" the client supports the new + // TextDocumentRegistrationOptions && StaticRegistrationOptions return + // value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// CallHierarchyPrepareParams params of CallHierarchyPrepare. +// +// @since 3.16.0. +type CallHierarchyPrepareParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +// CallHierarchyItem is the result of a "textDocument/prepareCallHierarchy" request. +// +// @since 3.16.0. +type CallHierarchyItem struct { + // name is the name of this item. + Name string `json:"name"` + + // Kind is the kind of this item. + Kind SymbolKind `json:"kind"` + + // Tags for this item. + Tags []SymbolTag `json:"tags,omitempty"` + + // Detail more detail for this item, e.g. the signature of a function. + Detail string `json:"detail,omitempty"` + + // URI is the resource identifier of this item. + URI DocumentURI `json:"uri"` + + // Range is the range enclosing this symbol not including leading/trailing whitespace + // but everything else, e.g. comments and code. + Range Range `json:"range"` + + // SelectionRange is the range that should be selected and revealed when this symbol is being + // picked, e.g. the name of a function. Must be contained by the + // Range. + SelectionRange Range `json:"selectionRange"` + + // Data is a data entry field that is preserved between a call hierarchy prepare and + // incoming calls or outgoing calls requests. + Data any `json:"data,omitempty"` +} + +// CallHierarchyIncomingCallsParams params of CallHierarchyIncomingCalls. +// +// @since 3.16.0. +type CallHierarchyIncomingCallsParams struct { + WorkDoneProgressParams + PartialResultParams + + // Item is the IncomingCalls item. + Item CallHierarchyItem `json:"item"` +} + +// CallHierarchyIncomingCall is the result of a "callHierarchy/incomingCalls" request. +// +// @since 3.16.0. +type CallHierarchyIncomingCall struct { + // From is the item that makes the call. + From CallHierarchyItem `json:"from"` + + // FromRanges is the ranges at which the calls appear. This is relative to the caller + // denoted by From. + FromRanges []Range `json:"fromRanges"` +} + +// CallHierarchyOutgoingCallsParams params of CallHierarchyOutgoingCalls. +// +// @since 3.16.0. +type CallHierarchyOutgoingCallsParams struct { + WorkDoneProgressParams + PartialResultParams + + // Item is the OutgoingCalls item. + Item CallHierarchyItem `json:"item"` +} + +// CallHierarchyOutgoingCall is the result of a "callHierarchy/outgoingCalls" request. +// +// @since 3.16.0. +type CallHierarchyOutgoingCall struct { + // To is the item that is called. + To CallHierarchyItem `json:"to"` + + // FromRanges is the range at which this item is called. This is the range relative to + // the caller, e.g the item passed to "callHierarchy/outgoingCalls" request. + FromRanges []Range `json:"fromRanges"` +} diff --git a/templ/lsp/protocol/callhierarchy_test.go b/templ/lsp/protocol/callhierarchy_test.go new file mode 100644 index 0000000..7329c88 --- /dev/null +++ b/templ/lsp/protocol/callhierarchy_test.go @@ -0,0 +1,1331 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/a-h/templ/lsp/uri" +) + +func TestCallHierarchy(t *testing.T) { + const ( + want = `{"dynamicRegistration":true}` + wantNil = `{}` + wantInvalid = `{"dynamicRegistration":false}` + ) + wantType := CallHierarchy{ + DynamicRegistration: true, + } + wantTypeNil := CallHierarchy{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchy + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchy + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchy + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCallHierarchyOptions(t *testing.T) { + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := CallHierarchyOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + wantTypeNil := CallHierarchyOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCallHierarchyRegistrationOptions(t *testing.T) { + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"workDoneProgress":true,"id":"testID"}` + wantNil = `{"documentSelector":[]}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := CallHierarchyRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + CallHierarchyOptions: CallHierarchyOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "testID", + }, + } + wantTypeNil := CallHierarchyRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{}, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCallHierarchyPrepareParams(t *testing.T) { + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `"}` + wantNil = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + invalidWorkDoneToken + `"}` + ) + wantType := CallHierarchyPrepareParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + } + wantTypeNil := CallHierarchyPrepareParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyPrepareParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyPrepareParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyPrepareParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCallHierarchyItem(t *testing.T) { + const ( + want = `{"name":"testName","kind":1,"tags":[1],"detail":"testDetail","uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"data":"testData"}` + wantNil = `{"name":"testName","kind":1,"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"name":"invalidName","kind":0,"tags":[0],"detail":"invalidDetail","uri":"file:///path/to/invalid.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"data":"invalidData"}` + ) + wantType := CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Detail: "testDetail", + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Data: "testData", + } + wantTypeNil := CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyItem + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyItem + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyItem + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCallHierarchyIncomingCallsParams(t *testing.T) { + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","item":{"name":"testName","kind":1,"tags":[1],"detail":"testDetail","uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"data":"testData"}}` + wantNil = `{"item":{"name":"testName","kind":1,"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","item":{"name":"invalidName","kind":0,"tags":[0],"detail":"invalidDetail","uri":"file:///path/to/invalid.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"data":"invalidData"}}` + ) + wantType := CallHierarchyIncomingCallsParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + Item: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Detail: "testDetail", + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Data: "testData", + }, + } + wantTypeNil := CallHierarchyIncomingCallsParams{ + Item: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyIncomingCallsParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyIncomingCallsParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyIncomingCallsParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCallHierarchyIncomingCall(t *testing.T) { + const ( + want = `{"from":{"name":"testName","kind":1,"tags":[1],"detail":"testDetail","uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"data":"testData"},"fromRanges":[{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}]}` + wantInvalid = `{"from":{"name":"invalidName","kind":0,"tags":[0],"detail":"invalidDetail","uri":"file:///path/to/invalid.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"data":"invalidData"},"fromRanges":[{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}]}` + ) + wantType := CallHierarchyIncomingCall{ + From: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Detail: "testDetail", + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Data: "testData", + }, + FromRanges: []Range{ + { + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyIncomingCall + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyIncomingCall + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyIncomingCall + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCallHierarchyOutgoingCallsParams(t *testing.T) { + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","item":{"name":"testName","kind":1,"tags":[1],"detail":"testDetail","uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"data":"testData"}}` + wantNil = `{"item":{"name":"testName","kind":1,"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","item":{"name":"invalidName","kind":0,"tags":[0],"detail":"invalidDetail","uri":"file:///path/to/invalid.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"data":"invalidData"}}` + ) + wantType := CallHierarchyOutgoingCallsParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + Item: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Detail: "testDetail", + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Data: "testData", + }, + } + wantTypeNil := CallHierarchyOutgoingCallsParams{ + Item: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyOutgoingCallsParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyOutgoingCallsParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyOutgoingCallsParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCallHierarchyOutgoingCall(t *testing.T) { + const ( + want = `{"to":{"name":"testName","kind":1,"tags":[1],"detail":"testDetail","uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"selectionRange":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"data":"testData"},"fromRanges":[{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}]}` + wantInvalid = `{"to":{"name":"invalidName","kind":0,"tags":[0],"detail":"invalidDetail","uri":"file:///path/to/invalid.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"data":"invalidData"},"fromRanges":[{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}]}` + ) + wantType := CallHierarchyOutgoingCall{ + To: CallHierarchyItem{ + Name: "testName", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Detail: "testDetail", + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Data: "testData", + }, + FromRanges: []Range{ + { + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CallHierarchyOutgoingCall + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CallHierarchyOutgoingCall + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CallHierarchyOutgoingCall + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/capabilities_client.go b/templ/lsp/protocol/capabilities_client.go new file mode 100644 index 0000000..3d80bef --- /dev/null +++ b/templ/lsp/protocol/capabilities_client.go @@ -0,0 +1,1068 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import "strconv" + +// ClientCapabilities now define capabilities for dynamic registration, workspace and text document features +// the client supports. +// +// The experimental can be used to pass experimental capabilities under development. +// +// For future compatibility a ClientCapabilities object literal can have more properties set than currently defined. +// Servers receiving a ClientCapabilities object literal with unknown properties should ignore these properties. +// +// A missing property should be interpreted as an absence of the capability. +// If a missing property normally defines sub properties, all missing sub properties should be interpreted +// as an absence of the corresponding capability. +type ClientCapabilities struct { + // Workspace specific client capabilities. + Workspace *WorkspaceClientCapabilities `json:"workspace,omitempty"` + + // TextDocument specific client capabilities. + TextDocument *TextDocumentClientCapabilities `json:"textDocument,omitempty"` + + // Window specific client capabilities. + Window *WindowClientCapabilities `json:"window,omitempty"` + + // General client capabilities. + // + // @since 3.16.0. + General *GeneralClientCapabilities `json:"general,omitempty"` + + // Experimental client capabilities. + Experimental any `json:"experimental,omitempty"` +} + +// WorkspaceClientCapabilities Workspace specific client capabilities. +type WorkspaceClientCapabilities struct { + // The client supports applying batch edits to the workspace by supporting + // the request "workspace/applyEdit". + ApplyEdit bool `json:"applyEdit,omitempty"` + + // WorkspaceEdit capabilities specific to `WorkspaceEdit`s. + WorkspaceEdit *WorkspaceClientCapabilitiesWorkspaceEdit `json:"workspaceEdit,omitempty"` + + // DidChangeConfiguration capabilities specific to the `workspace/didChangeConfiguration` notification. + DidChangeConfiguration *DidChangeConfigurationWorkspaceClientCapabilities `json:"didChangeConfiguration,omitempty"` + + // DidChangeWatchedFiles capabilities specific to the `workspace/didChangeWatchedFiles` notification. + DidChangeWatchedFiles *DidChangeWatchedFilesWorkspaceClientCapabilities `json:"didChangeWatchedFiles,omitempty"` + + // Symbol capabilities specific to the "workspace/symbol" request. + Symbol *WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"` + + // ExecuteCommand capabilities specific to the "workspace/executeCommand" request. + ExecuteCommand *ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"` + + // WorkspaceFolders is the client has support for workspace folders. + // + // @since 3.6.0. + WorkspaceFolders bool `json:"workspaceFolders,omitempty"` + + // Configuration is the client supports "workspace/configuration" requests. + // + // @since 3.6.0. + Configuration bool `json:"configuration,omitempty"` + + // SemanticTokens is the capabilities specific to the semantic token requests scoped to the + // workspace. + // + // @since 3.16.0. + SemanticTokens *SemanticTokensWorkspaceClientCapabilities `json:"semanticTokens,omitempty"` + + // CodeLens is the Capabilities specific to the code lens requests scoped to the + // workspace. + // + // @since 3.16.0. + CodeLens *CodeLensWorkspaceClientCapabilities `json:"codeLens,omitempty"` + + // FileOperations is the client has support for file requests/notifications. + // + // @since 3.16.0. + FileOperations *WorkspaceClientCapabilitiesFileOperations `json:"fileOperations,omitempty"` +} + +// WorkspaceClientCapabilitiesWorkspaceEdit capabilities specific to "WorkspaceEdit"s. +type WorkspaceClientCapabilitiesWorkspaceEdit struct { + // DocumentChanges is the client supports versioned document changes in `WorkspaceEdit`s + DocumentChanges bool `json:"documentChanges,omitempty"` + + // FailureHandling is the failure handling strategy of a client if applying the workspace edit + // fails. + // + // Mostly FailureHandlingKind. + FailureHandling string `json:"failureHandling,omitempty"` + + // ResourceOperations is the resource operations the client supports. Clients should at least + // support "create", "rename" and "delete" files and folders. + ResourceOperations []string `json:"resourceOperations,omitempty"` + + // NormalizesLineEndings whether the client normalizes line endings to the client specific + // setting. + // If set to `true` the client will normalize line ending characters + // in a workspace edit to the client specific new line character(s). + // + // @since 3.16.0. + NormalizesLineEndings bool `json:"normalizesLineEndings,omitempty"` + + // ChangeAnnotationSupport whether the client in general supports change annotations on text edits, + // create file, rename file and delete file changes. + // + // @since 3.16.0. + ChangeAnnotationSupport *WorkspaceClientCapabilitiesWorkspaceEditChangeAnnotationSupport `json:"changeAnnotationSupport,omitempty"` +} + +// FailureHandlingKind is the kind of failure handling . +type FailureHandlingKind string + +const ( + // FailureHandlingKindAbort applying the workspace change is simply aborted if one of the changes provided + // fails. All operations executed before the failing operation stay executed. + FailureHandlingKindAbort FailureHandlingKind = "abort" + + // FailureHandlingKindTransactional all operations are executed transactional. That means they either all + // succeed or no changes at all are applied to the workspace. + FailureHandlingKindTransactional FailureHandlingKind = "transactional" + + // FailureHandlingKindTextOnlyTransactional if the workspace edit contains only textual file changes they are executed transactional. + // If resource changes (create, rename or delete file) are part of the change the failure + // handling strategy is abort. + FailureHandlingKindTextOnlyTransactional FailureHandlingKind = "textOnlyTransactional" + + // FailureHandlingKindUndo the client tries to undo the operations already executed. But there is no + // guarantee that this is succeeding. + FailureHandlingKindUndo FailureHandlingKind = "undo" +) + +// WorkspaceClientCapabilitiesWorkspaceEditChangeAnnotationSupport is the ChangeAnnotationSupport of WorkspaceClientCapabilitiesWorkspaceEdit. +// +// @since 3.16.0. +type WorkspaceClientCapabilitiesWorkspaceEditChangeAnnotationSupport struct { + // GroupsOnLabel whether the client groups edits with equal labels into tree nodes, + // for instance all edits labeled with "Changes in Strings" would + // be a tree node. + GroupsOnLabel bool `json:"groupsOnLabel,omitempty"` +} + +// DidChangeConfigurationWorkspaceClientCapabilities capabilities specific to the "workspace/didChangeConfiguration" notification. +// +// @since 3.16.0. +type DidChangeConfigurationWorkspaceClientCapabilities struct { + // DynamicRegistration whether the did change configuration notification supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DidChangeWatchedFilesWorkspaceClientCapabilities capabilities specific to the "workspace/didChangeWatchedFiles" notification. +// +// @since 3.16.0. +type DidChangeWatchedFilesWorkspaceClientCapabilities struct { + // Did change watched files notification supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// WorkspaceSymbolClientCapabilities capabilities specific to the `workspace/symbol` request. +// +// WorkspaceSymbolClientCapabilities is the workspace symbol request is sent from the client to the server to +// list project-wide symbols matching the query string. +type WorkspaceSymbolClientCapabilities struct { + // DynamicRegistration is the Symbol request supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // SymbolKindCapabilities is the specific capabilities for the SymbolKindCapabilities in the "workspace/symbol" request. + SymbolKind *SymbolKindCapabilities `json:"symbolKind,omitempty"` + + // TagSupport is the client supports tags on `SymbolInformation`. + // Clients supporting tags have to handle unknown tags gracefully. + // + // @since 3.16.0 + TagSupport *TagSupportCapabilities `json:"tagSupport,omitempty"` +} + +type SymbolKindCapabilities struct { + // ValueSet is the symbol kind values the client supports. When this + // property exists the client also guarantees that it will + // handle values outside its set gracefully and falls back + // to a default value when unknown. + // + // If this property is not present the client only supports + // the symbol kinds from `File` to `Array` as defined in + // the initial version of the protocol. + ValueSet []SymbolKind `json:"valueSet,omitempty"` +} + +type TagSupportCapabilities struct { + // ValueSet is the tags supported by the client. + ValueSet []SymbolTag `json:"valueSet,omitempty"` +} + +// ExecuteCommandClientCapabilities capabilities specific to the "workspace/executeCommand" request. +type ExecuteCommandClientCapabilities struct { + // DynamicRegistration Execute command supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// SemanticTokensWorkspaceClientCapabilities capabilities specific to the "workspace/semanticToken" request. +// +// @since 3.16.0. +type SemanticTokensWorkspaceClientCapabilities struct { + // RefreshSupport whether the client implementation supports a refresh request sent from + // the server to the client. + // + // Note that this event is global and will force the client to refresh all + // semantic tokens currently shown. It should be used with absolute care + // and is useful for situation where a server for example detect a project + // wide change that requires such a calculation. + RefreshSupport bool `json:"refreshSupport,omitempty"` +} + +// CodeLensWorkspaceClientCapabilities capabilities specific to the "workspace/codeLens" request. +// +// @since 3.16.0. +type CodeLensWorkspaceClientCapabilities struct { + // RefreshSupport whether the client implementation supports a refresh request sent from the + // server to the client. + // + // Note that this event is global and will force the client to refresh all + // code lenses currently shown. It should be used with absolute care and is + // useful for situation where a server for example detect a project wide + // change that requires such a calculation. + RefreshSupport bool `json:"refreshSupport,omitempty"` +} + +// WorkspaceClientCapabilitiesFileOperations capabilities specific to the fileOperations. +// +// @since 3.16.0. +type WorkspaceClientCapabilitiesFileOperations struct { + // DynamicRegistration whether the client supports dynamic registration for file + // requests/notifications. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // DidCreate is the client has support for sending didCreateFiles notifications. + DidCreate bool `json:"didCreate,omitempty"` + + // WillCreate is the client has support for sending willCreateFiles requests. + WillCreate bool `json:"willCreate,omitempty"` + + // DidRename is the client has support for sending didRenameFiles notifications. + DidRename bool `json:"didRename,omitempty"` + + // WillRename is the client has support for sending willRenameFiles requests. + WillRename bool `json:"willRename,omitempty"` + + // DidDelete is the client has support for sending didDeleteFiles notifications. + DidDelete bool `json:"didDelete,omitempty"` + + // WillDelete is the client has support for sending willDeleteFiles requests. + WillDelete bool `json:"willDelete,omitempty"` +} + +// TextDocumentClientCapabilities Text document specific client capabilities. +type TextDocumentClientCapabilities struct { + // Synchronization defines which synchronization capabilities the client supports. + Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"` + + // Completion Capabilities specific to the "textDocument/completion". + Completion *CompletionTextDocumentClientCapabilities `json:"completion,omitempty"` + + // Hover capabilities specific to the "textDocument/hover". + Hover *HoverTextDocumentClientCapabilities `json:"hover,omitempty"` + + // SignatureHelp capabilities specific to the "textDocument/signatureHelp". + SignatureHelp *SignatureHelpTextDocumentClientCapabilities `json:"signatureHelp,omitempty"` + + // Declaration capabilities specific to the "textDocument/declaration". + Declaration *DeclarationTextDocumentClientCapabilities `json:"declaration,omitempty"` + + // Definition capabilities specific to the "textDocument/definition". + // + // @since 3.14.0. + Definition *DefinitionTextDocumentClientCapabilities `json:"definition,omitempty"` + + // TypeDefinition capabilities specific to the "textDocument/typeDefinition". + // + // @since 3.6.0. + TypeDefinition *TypeDefinitionTextDocumentClientCapabilities `json:"typeDefinition,omitempty"` + + // Implementation capabilities specific to the "textDocument/implementation". + // + // @since 3.6.0. + Implementation *ImplementationTextDocumentClientCapabilities `json:"implementation,omitempty"` + + // References capabilities specific to the "textDocument/references". + References *ReferencesTextDocumentClientCapabilities `json:"references,omitempty"` + + // DocumentHighlight capabilities specific to the "textDocument/documentHighlight". + DocumentHighlight *DocumentHighlightClientCapabilities `json:"documentHighlight,omitempty"` + + // DocumentSymbol capabilities specific to the "textDocument/documentSymbol". + DocumentSymbol *DocumentSymbolClientCapabilities `json:"documentSymbol,omitempty"` + + // CodeAction capabilities specific to the "textDocument/codeAction". + CodeAction *CodeActionClientCapabilities `json:"codeAction,omitempty"` + + // CodeLens capabilities specific to the "textDocument/codeLens". + CodeLens *CodeLensClientCapabilities `json:"codeLens,omitempty"` + + // DocumentLink capabilities specific to the "textDocument/documentLink". + DocumentLink *DocumentLinkClientCapabilities `json:"documentLink,omitempty"` + + // ColorProvider capabilities specific to the "textDocument/documentColor" and the + // "textDocument/colorPresentation" request. + // + // @since 3.6.0. + ColorProvider *DocumentColorClientCapabilities `json:"colorProvider,omitempty"` + + // Formatting Capabilities specific to the "textDocument/formatting" request. + Formatting *DocumentFormattingClientCapabilities `json:"formatting,omitempty"` + + // RangeFormatting Capabilities specific to the "textDocument/rangeFormatting" request. + RangeFormatting *DocumentRangeFormattingClientCapabilities `json:"rangeFormatting,omitempty"` + + // OnTypeFormatting Capabilities specific to the "textDocument/onTypeFormatting" request. + OnTypeFormatting *DocumentOnTypeFormattingClientCapabilities `json:"onTypeFormatting,omitempty"` + + // PublishDiagnostics capabilities specific to "textDocument/publishDiagnostics". + PublishDiagnostics *PublishDiagnosticsClientCapabilities `json:"publishDiagnostics,omitempty"` + + // Rename capabilities specific to the "textDocument/rename". + Rename *RenameClientCapabilities `json:"rename,omitempty"` + + // FoldingRange capabilities specific to "textDocument/foldingRange" requests. + // + // @since 3.10.0. + FoldingRange *FoldingRangeClientCapabilities `json:"foldingRange,omitempty"` + + // SelectionRange capabilities specific to "textDocument/selectionRange" requests. + // + // @since 3.15.0. + SelectionRange *SelectionRangeClientCapabilities `json:"selectionRange,omitempty"` + + // CallHierarchy capabilities specific to the various call hierarchy requests. + // + // @since 3.16.0. + CallHierarchy *CallHierarchyClientCapabilities `json:"callHierarchy,omitempty"` + + // SemanticTokens capabilities specific to the various semantic token requests. + // + // @since 3.16.0. + SemanticTokens *SemanticTokensClientCapabilities `json:"semanticTokens,omitempty"` + + // LinkedEditingRange capabilities specific to the "textDocument/linkedEditingRange" request. + // + // @since 3.16.0. + LinkedEditingRange *LinkedEditingRangeClientCapabilities `json:"linkedEditingRange,omitempty"` + + // Moniker capabilities specific to the "textDocument/moniker" request. + // + // @since 3.16.0. + Moniker *MonikerClientCapabilities `json:"moniker,omitempty"` +} + +// TextDocumentSyncClientCapabilities defines which synchronization capabilities the client supports. +type TextDocumentSyncClientCapabilities struct { + // DynamicRegistration whether text document synchronization supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // WillSave is the client supports sending will save notifications. + WillSave bool `json:"willSave,omitempty"` + + // WillSaveWaitUntil is the client supports sending a will save request and + // waits for a response providing text edits which will + // be applied to the document before it is saved. + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + + // DidSave is the client supports did save notifications. + DidSave bool `json:"didSave,omitempty"` +} + +// CompletionTextDocumentClientCapabilities Capabilities specific to the "textDocument/completion". +type CompletionTextDocumentClientCapabilities struct { + // Whether completion supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // The client supports the following `CompletionItem` specific + // capabilities. + CompletionItem *CompletionTextDocumentClientCapabilitiesItem `json:"completionItem,omitempty"` + + CompletionItemKind *CompletionTextDocumentClientCapabilitiesItemKind `json:"completionItemKind,omitempty"` + + // ContextSupport is the client supports to send additional context information for a + // `textDocument/completion` request. + ContextSupport bool `json:"contextSupport,omitempty"` +} + +// CompletionTextDocumentClientCapabilitiesItem is the client supports the following "CompletionItem" specific +// capabilities. +type CompletionTextDocumentClientCapabilitiesItem struct { + // SnippetSupport client supports snippets as insert text. + // + // A snippet can define tab stops and placeholders with `$1`, `$2` + // and `${3:foo}`. `$0` defines the final tab stop, it defaults to + // the end of the snippet. Placeholders with equal identifiers are linked, + // that is typing in one will update others too. + SnippetSupport bool `json:"snippetSupport,omitempty"` + + // CommitCharactersSupport client supports commit characters on a completion item. + CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"` + + // DocumentationFormat client supports the follow content formats for the documentation + // property. The order describes the preferred format of the client. + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + // DeprecatedSupport client supports the deprecated property on a completion item. + DeprecatedSupport bool `json:"deprecatedSupport,omitempty"` + + // PreselectSupport client supports the preselect property on a completion item. + PreselectSupport bool `json:"preselectSupport,omitempty"` + + // TagSupport is the client supports the tag property on a completion item. + // + // Clients supporting tags have to handle unknown tags gracefully. + // Clients especially need to preserve unknown tags when sending + // a completion item back to the server in a resolve call. + // + // @since 3.15.0. + TagSupport *CompletionTextDocumentClientCapabilitiesItemTagSupport `json:"tagSupport,omitempty"` + + // InsertReplaceSupport client supports insert replace edit to control different behavior if + // a completion item is inserted in the text or should replace text. + // + // @since 3.16.0. + InsertReplaceSupport bool `json:"insertReplaceSupport,omitempty"` + + // ResolveSupport indicates which properties a client can resolve lazily on a + // completion item. Before version 3.16.0 only the predefined properties + // `documentation` and `details` could be resolved lazily. + // + // @since 3.16.0. + ResolveSupport *CompletionTextDocumentClientCapabilitiesItemResolveSupport `json:"resolveSupport,omitempty"` + + // InsertTextModeSupport is the client supports the `insertTextMode` property on + // a completion item to override the whitespace handling mode + // as defined by the client (see `insertTextMode`). + // + // @since 3.16.0. + InsertTextModeSupport *CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport `json:"insertTextModeSupport,omitempty"` +} + +// CompletionTextDocumentClientCapabilitiesItemTagSupport specific capabilities for the "TagSupport" in the "textDocument/completion" request. +// +// @since 3.15.0. +type CompletionTextDocumentClientCapabilitiesItemTagSupport struct { + // ValueSet is the tags supported by the client. + // + // @since 3.15.0. + ValueSet []CompletionItemTag `json:"valueSet,omitempty"` +} + +// CompletionTextDocumentClientCapabilitiesItemResolveSupport specific capabilities for the ResolveSupport in the CompletionTextDocumentClientCapabilitiesItem. +// +// @since 3.16.0. +type CompletionTextDocumentClientCapabilitiesItemResolveSupport struct { + // Properties is the properties that a client can resolve lazily. + Properties []string `json:"properties"` +} + +// CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport specific capabilities for the InsertTextModeSupport in the CompletionTextDocumentClientCapabilitiesItem. +// +// @since 3.16.0. +type CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport struct { + // ValueSet is the tags supported by the client. + // + // @since 3.16.0. + ValueSet []InsertTextMode `json:"valueSet,omitempty"` +} + +// CompletionTextDocumentClientCapabilitiesItemKind specific capabilities for the "CompletionItemKind" in the "textDocument/completion" request. +type CompletionTextDocumentClientCapabilitiesItemKind struct { + // The completion item kind values the client supports. When this + // property exists the client also guarantees that it will + // handle values outside its set gracefully and falls back + // to a default value when unknown. + // + // If this property is not present the client only supports + // the completion items kinds from `Text` to `Reference` as defined in + // the initial version of the protocol. + // + ValueSet []CompletionItemKind `json:"valueSet,omitempty"` +} + +// HoverTextDocumentClientCapabilities capabilities specific to the "textDocument/hover". +type HoverTextDocumentClientCapabilities struct { + // DynamicRegistration whether hover supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // ContentFormat is the client supports the follow content formats for the content + // property. The order describes the preferred format of the client. + ContentFormat []MarkupKind `json:"contentFormat,omitempty"` +} + +// SignatureHelpTextDocumentClientCapabilities capabilities specific to the "textDocument/signatureHelp". +type SignatureHelpTextDocumentClientCapabilities struct { + // DynamicRegistration whether signature help supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // SignatureInformation is the client supports the following "SignatureInformation" + // specific properties. + SignatureInformation *TextDocumentClientCapabilitiesSignatureInformation `json:"signatureInformation,omitempty"` + + // ContextSupport is the client supports to send additional context information for a "textDocument/signatureHelp" request. + // + // A client that opts into contextSupport will also support the "retriggerCharacters" on "SignatureHelpOptions". + // + // @since 3.15.0. + ContextSupport bool `json:"contextSupport,omitempty"` +} + +// TextDocumentClientCapabilitiesSignatureInformation is the client supports the following "SignatureInformation" +// specific properties. +type TextDocumentClientCapabilitiesSignatureInformation struct { + // DocumentationFormat is the client supports the follow content formats for the documentation + // property. The order describes the preferred format of the client. + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + // ParameterInformation is the Client capabilities specific to parameter information. + ParameterInformation *TextDocumentClientCapabilitiesParameterInformation `json:"parameterInformation,omitempty"` + + // ActiveParameterSupport is the client supports the `activeParameter` property on + // `SignatureInformation` literal. + // + // @since 3.16.0. + ActiveParameterSupport bool `json:"activeParameterSupport,omitempty"` +} + +// TextDocumentClientCapabilitiesParameterInformation is the client capabilities specific to parameter information. +type TextDocumentClientCapabilitiesParameterInformation struct { + // LabelOffsetSupport is the client supports processing label offsets instead of a + // simple label string. + // + // @since 3.14.0. + LabelOffsetSupport bool `json:"labelOffsetSupport,omitempty"` +} + +// DeclarationTextDocumentClientCapabilities capabilities specific to the "textDocument/declaration". +type DeclarationTextDocumentClientCapabilities struct { + // DynamicRegistration whether declaration supports dynamic registration. If this is set to `true` + // the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // LinkSupport is the client supports additional metadata in the form of declaration links. + // + // @since 3.14.0. + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// DefinitionTextDocumentClientCapabilities capabilities specific to the "textDocument/definition". +// +// @since 3.14.0. +type DefinitionTextDocumentClientCapabilities struct { + // DynamicRegistration whether definition supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // LinkSupport is the client supports additional metadata in the form of definition links. + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// TypeDefinitionTextDocumentClientCapabilities capabilities specific to the "textDocument/typeDefinition". +// +// @since 3.6.0. +type TypeDefinitionTextDocumentClientCapabilities struct { + // DynamicRegistration whether typeDefinition supports dynamic registration. If this is set to `true` + // the client supports the new "(TextDocumentRegistrationOptions & StaticRegistrationOptions)" + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // LinkSupport is the client supports additional metadata in the form of definition links. + // + // @since 3.14.0 + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// ImplementationTextDocumentClientCapabilities capabilities specific to the "textDocument/implementation". +// +// @since 3.6.0. +type ImplementationTextDocumentClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration. If this is set to `true` + // the client supports the new "(TextDocumentRegistrationOptions & StaticRegistrationOptions)" + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // LinkSupport is the client supports additional metadata in the form of definition links. + // + // @since 3.14.0 + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// ReferencesTextDocumentClientCapabilities capabilities specific to the "textDocument/references". +type ReferencesTextDocumentClientCapabilities struct { + // DynamicRegistration whether references supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentHighlightClientCapabilities capabilities specific to the "textDocument/documentHighlight". +type DocumentHighlightClientCapabilities struct { + // DynamicRegistration Whether document highlight supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentSymbolClientCapabilities capabilities specific to the "textDocument/documentSymbol". +type DocumentSymbolClientCapabilities struct { + // DynamicRegistration whether document symbol supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // SymbolKind specific capabilities for the "SymbolKindCapabilities". + SymbolKind *SymbolKindCapabilities `json:"symbolKind,omitempty"` + + // HierarchicalDocumentSymbolSupport is the client support hierarchical document symbols. + HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"` + + // TagSupport is the client supports tags on "SymbolInformation". Tags are supported on + // "DocumentSymbol" if "HierarchicalDocumentSymbolSupport" is set to true. + // Clients supporting tags have to handle unknown tags gracefully. + // + // @since 3.16.0. + TagSupport *DocumentSymbolClientCapabilitiesTagSupport `json:"tagSupport,omitempty"` + + // LabelSupport is the client supports an additional label presented in the UI when + // registering a document symbol provider. + // + // @since 3.16.0. + LabelSupport bool `json:"labelSupport,omitempty"` +} + +// DocumentSymbolClientCapabilitiesTagSupport TagSupport in the DocumentSymbolClientCapabilities. +// +// @since 3.16.0. +type DocumentSymbolClientCapabilitiesTagSupport struct { + // ValueSet is the tags supported by the client. + ValueSet []SymbolTag `json:"valueSet"` +} + +// CodeActionClientCapabilities capabilities specific to the "textDocument/codeAction". +type CodeActionClientCapabilities struct { + // DynamicRegistration whether code action supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // CodeActionLiteralSupport is the client support code action literals as a valid + // response of the "textDocument/codeAction" request. + // + // @since 3.8.0 + CodeActionLiteralSupport *CodeActionClientCapabilitiesLiteralSupport `json:"codeActionLiteralSupport,omitempty"` + + // IsPreferredSupport whether code action supports the "isPreferred" property. + // + // @since 3.15.0. + IsPreferredSupport bool `json:"isPreferredSupport,omitempty"` + + // DisabledSupport whether code action supports the `disabled` property. + // + // @since 3.16.0. + DisabledSupport bool `json:"disabledSupport,omitempty"` + + // DataSupport whether code action supports the `data` property which is + // preserved between a `textDocument/codeAction` and a + // `codeAction/resolve` request. + // + // @since 3.16.0. + DataSupport bool `json:"dataSupport,omitempty"` + + // ResolveSupport whether the client supports resolving additional code action + // properties via a separate `codeAction/resolve` request. + // + // @since 3.16.0. + ResolveSupport *CodeActionClientCapabilitiesResolveSupport `json:"resolveSupport,omitempty"` + + // HonorsChangeAnnotations whether the client honors the change annotations in + // text edits and resource operations returned via the + // `CodeAction#edit` property by for example presenting + // the workspace edit in the user interface and asking + // for confirmation. + // + // @since 3.16.0. + HonorsChangeAnnotations bool `json:"honorsChangeAnnotations,omitempty"` +} + +// CodeActionClientCapabilitiesLiteralSupport is the client support code action literals as a valid response of the "textDocument/codeAction" request. +type CodeActionClientCapabilitiesLiteralSupport struct { + // CodeActionKind is the code action kind is support with the following value + // set. + CodeActionKind *CodeActionClientCapabilitiesKind `json:"codeActionKind"` +} + +// CodeActionClientCapabilitiesKind is the code action kind is support with the following value set. +type CodeActionClientCapabilitiesKind struct { + // ValueSet is the code action kind values the client supports. When this + // property exists the client also guarantees that it will + // handle values outside its set gracefully and falls back + // to a default value when unknown. + ValueSet []CodeActionKind `json:"valueSet"` +} + +// CodeActionClientCapabilitiesResolveSupport ResolveSupport in the CodeActionClientCapabilities. +// +// @since 3.16.0. +type CodeActionClientCapabilitiesResolveSupport struct { + // Properties is the properties that a client can resolve lazily. + Properties []string `json:"properties"` +} + +// CodeLensClientCapabilities capabilities specific to the "textDocument/codeLens". +type CodeLensClientCapabilities struct { + // DynamicRegistration Whether code lens supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentLinkClientCapabilities capabilities specific to the "textDocument/documentLink". +type DocumentLinkClientCapabilities struct { + // DynamicRegistration whether document link supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // TooltipSupport whether the client supports the "tooltip" property on "DocumentLink". + // + // @since 3.15.0. + TooltipSupport bool `json:"tooltipSupport,omitempty"` +} + +// DocumentColorClientCapabilities capabilities specific to the "textDocument/documentColor" and the +// "textDocument/colorPresentation" request. +// +// @since 3.6.0. +type DocumentColorClientCapabilities struct { + // DynamicRegistration whether colorProvider supports dynamic registration. If this is set to `true` + // the client supports the new "(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)" + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentFormattingClientCapabilities capabilities specific to the "textDocument/formatting". +type DocumentFormattingClientCapabilities struct { + // DynamicRegistration whether code lens supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentRangeFormattingClientCapabilities capabilities specific to the "textDocument/rangeFormatting". +type DocumentRangeFormattingClientCapabilities struct { + // DynamicRegistration whether code lens supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentOnTypeFormattingClientCapabilities capabilities specific to the "textDocument/onTypeFormatting". +type DocumentOnTypeFormattingClientCapabilities struct { + // DynamicRegistration whether code lens supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// PublishDiagnosticsClientCapabilities capabilities specific to "textDocument/publishDiagnostics". +type PublishDiagnosticsClientCapabilities struct { + // RelatedInformation whether the clients accepts diagnostics with related information. + RelatedInformation bool `json:"relatedInformation,omitempty"` + + // TagSupport clients supporting tags have to handle unknown tags gracefully. + // + // @since 3.15.0. + TagSupport *PublishDiagnosticsClientCapabilitiesTagSupport `json:"tagSupport,omitempty"` + + // VersionSupport whether the client interprets the version property of the + // "textDocument/publishDiagnostics" notification`s parameter. + // + // @since 3.15.0. + VersionSupport bool `json:"versionSupport,omitempty"` + + // CodeDescriptionSupport client supports a codeDescription property + // + // @since 3.16.0. + CodeDescriptionSupport bool `json:"codeDescriptionSupport,omitempty"` + + // DataSupport whether code action supports the `data` property which is + // preserved between a `textDocument/publishDiagnostics` and + // `textDocument/codeAction` request. + // + // @since 3.16.0. + DataSupport bool `json:"dataSupport,omitempty"` +} + +// PublishDiagnosticsClientCapabilitiesTagSupport is the client capacity of TagSupport. +// +// @since 3.15.0. +type PublishDiagnosticsClientCapabilitiesTagSupport struct { + // ValueSet is the tags supported by the client. + ValueSet []DiagnosticTag `json:"valueSet"` +} + +// RenameClientCapabilities capabilities specific to the "textDocument/rename". +type RenameClientCapabilities struct { + // DynamicRegistration whether rename supports dynamic registration. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // PrepareSupport is the client supports testing for validity of rename operations + // before execution. + PrepareSupport bool `json:"prepareSupport,omitempty"` + + // PrepareSupportDefaultBehavior client supports the default behavior result + // (`{ defaultBehavior: boolean }`). + // + // The value indicates the default behavior used by the + // client. + // + // @since 3.16.0. + PrepareSupportDefaultBehavior PrepareSupportDefaultBehavior `json:"prepareSupportDefaultBehavior,omitempty"` + + // HonorsChangeAnnotations whether th client honors the change annotations in + // text edits and resource operations returned via the + // rename request's workspace edit by for example presenting + // the workspace edit in the user interface and asking + // for confirmation. + // + // @since 3.16.0. + HonorsChangeAnnotations bool `json:"honorsChangeAnnotations,omitempty"` +} + +// PrepareSupportDefaultBehavior default behavior of PrepareSupport. +// +// @since 3.16.0. +type PrepareSupportDefaultBehavior float64 + +// list of PrepareSupportDefaultBehavior. +const ( + // PrepareSupportDefaultBehaviorIdentifier is the client's default behavior is to select the identifier + // according the to language's syntax rule. + PrepareSupportDefaultBehaviorIdentifier PrepareSupportDefaultBehavior = 1 +) + +// String returns a string representation of the PrepareSupportDefaultBehavior. +func (k PrepareSupportDefaultBehavior) String() string { + switch k { + case PrepareSupportDefaultBehaviorIdentifier: + return "Identifier" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// FoldingRangeClientCapabilities capabilities specific to "textDocument/foldingRange" requests. +// +// @since 3.10.0. +type FoldingRangeClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration for folding range providers. If this is set to `true` + // the client supports the new "(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)" + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // RangeLimit is the maximum number of folding ranges that the client prefers to receive per document. The value serves as a + // hint, servers are free to follow the limit. + RangeLimit uint32 `json:"rangeLimit,omitempty"` + + // LineFoldingOnly if set, the client signals that it only supports folding complete lines. If set, client will + // ignore specified "startCharacter" and "endCharacter" properties in a FoldingRange. + LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"` +} + +// SelectionRangeClientCapabilities capabilities specific to "textDocument/selectionRange" requests. +// +// @since 3.16.0. +type SelectionRangeClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration for selection range providers. If this is set to `true` + // the client supports the new "(SelectionRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)" + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// CallHierarchyClientCapabilities capabilities specific to "textDocument/callHierarchy" requests. +// +// @since 3.16.0. +type CallHierarchyClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration. If this is set to + // `true` the client supports the new `(TextDocumentRegistrationOptions & + // StaticRegistrationOptions)` return value for the corresponding server + // capability as well.} + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// SemanticTokensClientCapabilities capabilities specific to the "textDocument.semanticTokens" request. +// +// @since 3.16.0. +type SemanticTokensClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration. If this is set to + // `true` the client supports the new `(TextDocumentRegistrationOptions & + // StaticRegistrationOptions)` return value for the corresponding server + // capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + // Requests which requests the client supports and might send to the server + // depending on the server's capability. Please note that clients might not + // show semantic tokens or degrade some of the user experience if a range + // or full request is advertised by the client but not provided by the + // server. If for example the client capability `requests.full` and + // `request.range` are both set to true but the server only provides a + // range provider the client might not render a minimap correctly or might + // even decide to not show any semantic tokens at all. + Requests SemanticTokensWorkspaceClientCapabilitiesRequests `json:"requests"` + + // TokenTypes is the token types that the client supports. + TokenTypes []string `json:"tokenTypes"` + + // TokenModifiers is the token modifiers that the client supports. + TokenModifiers []string `json:"tokenModifiers"` + + // Formats is the formats the clients supports. + Formats []TokenFormat `json:"formats"` + + // OverlappingTokenSupport whether the client supports tokens that can overlap each other. + OverlappingTokenSupport bool `json:"overlappingTokenSupport,omitempty"` + + // MultilineTokenSupport whether the client supports tokens that can span multiple lines. + MultilineTokenSupport bool `json:"multilineTokenSupport,omitempty"` +} + +// SemanticTokensWorkspaceClientCapabilitiesRequests capabilities specific to the "textDocument/semanticTokens/xxx" request. +// +// @since 3.16.0. +type SemanticTokensWorkspaceClientCapabilitiesRequests struct { + // Range is the client will send the "textDocument/semanticTokens/range" request + // if the server provides a corresponding handler. + Range bool `json:"range,omitempty"` + + // Full is the client will send the "textDocument/semanticTokens/full" request + // if the server provides a corresponding handler. The client will send the + // `textDocument/semanticTokens/full/delta` request if the server provides a + // corresponding handler. + Full any `json:"full,omitempty"` +} + +// LinkedEditingRangeClientCapabilities capabilities specific to "textDocument/linkedEditingRange" requests. +// +// @since 3.16.0. +type LinkedEditingRangeClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration. + // If this is set to `true` the client supports the new + // `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + // return value for the corresponding server capability as well. + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// MonikerClientCapabilities capabilities specific to the "textDocument/moniker" request. +// +// @since 3.16.0. +type MonikerClientCapabilities struct { + // DynamicRegistration whether implementation supports dynamic registration. If this is set to + // `true` the client supports the new `(TextDocumentRegistrationOptions & + // StaticRegistrationOptions)` return value for the corresponding server + // capability as well.// DynamicRegistration whether implementation supports dynamic registration. If this is set to + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// WindowClientCapabilities represents a WindowClientCapabilities specific client capabilities. +// +// @since 3.15.0. +type WindowClientCapabilities struct { + // WorkDoneProgress whether client supports handling progress notifications. If set servers are allowed to + // report in "workDoneProgress" property in the request specific server capabilities. + // + // @since 3.15.0. + WorkDoneProgress bool `json:"workDoneProgress,omitempty"` + + // ShowMessage capabilities specific to the showMessage request. + // + // @since 3.16.0. + ShowMessage *ShowMessageRequestClientCapabilities `json:"showMessage,omitempty"` + + // ShowDocument client capabilities for the show document request. + // + // @since 3.16.0. + ShowDocument *ShowDocumentClientCapabilities `json:"showDocument,omitempty"` +} + +// ShowMessageRequestClientCapabilities show message request client capabilities. +// +// @since 3.16.0. +type ShowMessageRequestClientCapabilities struct { + // MessageActionItem capabilities specific to the "MessageActionItem" type. + MessageActionItem *ShowMessageRequestClientCapabilitiesMessageActionItem `json:"messageActionItem,omitempty"` +} + +// ShowMessageRequestClientCapabilitiesMessageActionItem capabilities specific to the "MessageActionItem" type. +// +// @since 3.16.0. +type ShowMessageRequestClientCapabilitiesMessageActionItem struct { + // AdditionalPropertiesSupport whether the client supports additional attributes which + // are preserved and sent back to the server in the + // request's response. + AdditionalPropertiesSupport bool `json:"additionalPropertiesSupport,omitempty"` +} + +// ShowDocumentClientCapabilities client capabilities for the show document request. +// +// @since 3.16.0. +type ShowDocumentClientCapabilities struct { + // Support is the client has support for the show document + // request. + Support bool `json:"support"` +} + +// GeneralClientCapabilities represents a General specific client capabilities. +// +// @since 3.16.0. +type GeneralClientCapabilities struct { + // RegularExpressions is the client capabilities specific to regular expressions. + // + // @since 3.16.0. + RegularExpressions *RegularExpressionsClientCapabilities `json:"regularExpressions,omitempty"` + + // Markdown client capabilities specific to the client's markdown parser. + // + // @since 3.16.0. + Markdown *MarkdownClientCapabilities `json:"markdown,omitempty"` +} + +// RegularExpressionsClientCapabilities represents a client capabilities specific to regular expressions. +// +// The following features from the ECMAScript 2020 regular expression specification are NOT mandatory for a client: +// +// Assertions +// +// Lookahead assertion, Negative lookahead assertion, lookbehind assertion, negative lookbehind assertion. +// +// Character classes +// +// Matching control characters using caret notation (e.g. "\cX") and matching UTF-16 code units (e.g. "\uhhhh"). +// +// Group and ranges +// +// Named capturing groups. +// +// Unicode property escapes +// +// None of the features needs to be supported. +// +// The only regular expression flag that a client needs to support is "i" to specify a case insensitive search. +// +// @since 3.16.0. +type RegularExpressionsClientCapabilities struct { + // Engine is the engine's name. + // + // Well known engine name is "ECMAScript". + // https://tc39.es/ecma262/#sec-regexp-regular-expression-objects + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + Engine string `json:"engine"` + + // Version is the engine's version. + // + // Well known engine version is "ES2020". + // https://tc39.es/ecma262/#sec-regexp-regular-expression-objects + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions + Version string `json:"version,omitempty"` +} + +// MarkdownClientCapabilities represents a client capabilities specific to the used markdown parser. +// +// @since 3.16.0. +type MarkdownClientCapabilities struct { + // Parser is the name of the parser. + Parser string `json:"parser"` + + // version is the version of the parser. + Version string `json:"version,omitempty"` +} diff --git a/templ/lsp/protocol/capabilities_client_test.go b/templ/lsp/protocol/capabilities_client_test.go new file mode 100644 index 0000000..dbb2d94 --- /dev/null +++ b/templ/lsp/protocol/capabilities_client_test.go @@ -0,0 +1,2787 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" +) + +func TestClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"failureHandling":"FailureHandling","resourceOperations":["ResourceOperations"]},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6]}},"executeCommand":{"dynamicRegistration":true},"workspaceFolders":true,"configuration":true},"textDocument":{"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["plaintext","markdown"],"deprecatedSupport":true,"preselectSupport":true},"completionItemKind":{"valueSet":[1]},"contextSupport":true},"hover":{"dynamicRegistration":true,"contentFormat":["plaintext","markdown"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["plaintext","markdown"]}},"declaration":{"dynamicRegistration":true,"linkSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6]},"hierarchicalDocumentSymbolSupport":true},"codeAction":{"dynamicRegistration":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"documentLink":{"dynamicRegistration":true},"colorProvider":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"publishDiagnostics":{"relatedInformation":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5,"lineFoldingOnly":true},"selectionRange":{"dynamicRegistration":true},"callHierarchy":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"requests":{"range":true,"full":true},"tokenTypes":["test","tokenTypes"],"tokenModifiers":["test","tokenModifiers"],"formats":["relative"],"overlappingTokenSupport":true,"multilineTokenSupport":true},"linkedEditingRange":{"dynamicRegistration":true},"moniker":{"dynamicRegistration":true}},"window":{"workDoneProgress":true,"showMessage":{"messageActionItem":{"additionalPropertiesSupport":true}},"showDocument":{"support":true}},"general":{"regularExpressions":{"engine":"ECMAScript","version":"ES2020"},"markdown":{"parser":"marked","version":"1.1.0"}},"experimental":"testExperimental"}` + wantNil = `{}` + ) + wantType := ClientCapabilities{ + Workspace: &WorkspaceClientCapabilities{ + ApplyEdit: true, + WorkspaceEdit: &WorkspaceClientCapabilitiesWorkspaceEdit{ + DocumentChanges: true, + FailureHandling: "FailureHandling", + ResourceOperations: []string{"ResourceOperations"}, + }, + DidChangeConfiguration: &DidChangeConfigurationWorkspaceClientCapabilities{ + DynamicRegistration: true, + }, + DidChangeWatchedFiles: &DidChangeWatchedFilesWorkspaceClientCapabilities{ + DynamicRegistration: true, + }, + Symbol: &WorkspaceSymbolClientCapabilities{ + DynamicRegistration: true, + SymbolKind: &SymbolKindCapabilities{ + ValueSet: []SymbolKind{ + SymbolKindFile, + SymbolKindModule, + SymbolKindNamespace, + SymbolKindPackage, + SymbolKindClass, + SymbolKindMethod, + }, + }, + }, + ExecuteCommand: &ExecuteCommandClientCapabilities{ + DynamicRegistration: true, + }, + WorkspaceFolders: true, + Configuration: true, + }, + TextDocument: &TextDocumentClientCapabilities{ + Synchronization: &TextDocumentSyncClientCapabilities{ + DynamicRegistration: true, + WillSave: true, + WillSaveWaitUntil: true, + DidSave: true, + }, + Completion: &CompletionTextDocumentClientCapabilities{ + DynamicRegistration: true, + CompletionItem: &CompletionTextDocumentClientCapabilitiesItem{ + SnippetSupport: true, + CommitCharactersSupport: true, + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + DeprecatedSupport: true, + PreselectSupport: true, + }, + CompletionItemKind: &CompletionTextDocumentClientCapabilitiesItemKind{ + ValueSet: []CompletionItemKind{CompletionItemKindText}, + }, + ContextSupport: true, + }, + Hover: &HoverTextDocumentClientCapabilities{ + DynamicRegistration: true, + ContentFormat: []MarkupKind{ + PlainText, + Markdown, + }, + }, + SignatureHelp: &SignatureHelpTextDocumentClientCapabilities{ + DynamicRegistration: true, + SignatureInformation: &TextDocumentClientCapabilitiesSignatureInformation{ + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + }, + }, + Declaration: &DeclarationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + Definition: &DefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + TypeDefinition: &TypeDefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + Implementation: &ImplementationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + References: &ReferencesTextDocumentClientCapabilities{ + DynamicRegistration: true, + }, + DocumentHighlight: &DocumentHighlightClientCapabilities{ + DynamicRegistration: true, + }, + DocumentSymbol: &DocumentSymbolClientCapabilities{ + DynamicRegistration: true, + SymbolKind: &SymbolKindCapabilities{ + ValueSet: []SymbolKind{ + SymbolKindFile, + SymbolKindModule, + SymbolKindNamespace, + SymbolKindPackage, + SymbolKindClass, + SymbolKindMethod, + }, + }, + HierarchicalDocumentSymbolSupport: true, + }, + CodeAction: &CodeActionClientCapabilities{ + DynamicRegistration: true, + CodeActionLiteralSupport: &CodeActionClientCapabilitiesLiteralSupport{ + CodeActionKind: &CodeActionClientCapabilitiesKind{ + ValueSet: []CodeActionKind{ + QuickFix, + Refactor, + RefactorExtract, + RefactorRewrite, + Source, + SourceOrganizeImports, + }, + }, + }, + }, + CodeLens: &CodeLensClientCapabilities{ + DynamicRegistration: true, + }, + DocumentLink: &DocumentLinkClientCapabilities{ + DynamicRegistration: true, + }, + ColorProvider: &DocumentColorClientCapabilities{ + DynamicRegistration: true, + }, + Formatting: &DocumentFormattingClientCapabilities{ + DynamicRegistration: true, + }, + RangeFormatting: &DocumentRangeFormattingClientCapabilities{ + DynamicRegistration: true, + }, + OnTypeFormatting: &DocumentOnTypeFormattingClientCapabilities{ + DynamicRegistration: true, + }, + PublishDiagnostics: &PublishDiagnosticsClientCapabilities{ + RelatedInformation: true, + }, + Rename: &RenameClientCapabilities{ + DynamicRegistration: true, + PrepareSupport: true, + }, + FoldingRange: &FoldingRangeClientCapabilities{ + DynamicRegistration: true, + RangeLimit: uint32(5), + LineFoldingOnly: true, + }, + SelectionRange: &SelectionRangeClientCapabilities{ + DynamicRegistration: true, + }, + CallHierarchy: &CallHierarchyClientCapabilities{ + DynamicRegistration: true, + }, + SemanticTokens: &SemanticTokensClientCapabilities{ + DynamicRegistration: true, + Requests: SemanticTokensWorkspaceClientCapabilitiesRequests{ + Range: true, + Full: true, + }, + TokenTypes: []string{"test", "tokenTypes"}, + TokenModifiers: []string{"test", "tokenModifiers"}, + Formats: []TokenFormat{ + TokenFormatRelative, + }, + OverlappingTokenSupport: true, + MultilineTokenSupport: true, + }, + LinkedEditingRange: &LinkedEditingRangeClientCapabilities{ + DynamicRegistration: true, + }, + Moniker: &MonikerClientCapabilities{ + DynamicRegistration: true, + }, + }, + Window: &WindowClientCapabilities{ + WorkDoneProgress: true, + ShowMessage: &ShowMessageRequestClientCapabilities{ + MessageActionItem: &ShowMessageRequestClientCapabilitiesMessageActionItem{ + AdditionalPropertiesSupport: true, + }, + }, + ShowDocument: &ShowDocumentClientCapabilities{ + Support: true, + }, + }, + General: &GeneralClientCapabilities{ + RegularExpressions: &RegularExpressionsClientCapabilities{ + Engine: "ECMAScript", + Version: "ES2020", + }, + Markdown: &MarkdownClientCapabilities{ + Parser: "marked", + Version: "1.1.0", + }, + }, + Experimental: "testExperimental", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: ClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: ClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkspaceClientCapabilities(t *testing.T) { + t.Parallel() + + const want = `{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"failureHandling":"FailureHandling","resourceOperations":["ResourceOperations"],"normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnLabel":true}},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6]}},"executeCommand":{"dynamicRegistration":true},"workspaceFolders":true,"configuration":true,"semanticTokens":{"refreshSupport":true},"codeLens":{"refreshSupport":true},"fileOperations":{"dynamicRegistration":true,"didCreate":true,"willCreate":true,"didRename":true,"willRename":true,"didDelete":true,"willDelete":true}}` + wantType := WorkspaceClientCapabilities{ + ApplyEdit: true, + WorkspaceEdit: &WorkspaceClientCapabilitiesWorkspaceEdit{ + DocumentChanges: true, + FailureHandling: "FailureHandling", + ResourceOperations: []string{"ResourceOperations"}, + NormalizesLineEndings: true, + ChangeAnnotationSupport: &WorkspaceClientCapabilitiesWorkspaceEditChangeAnnotationSupport{ + GroupsOnLabel: true, + }, + }, + DidChangeConfiguration: &DidChangeConfigurationWorkspaceClientCapabilities{ + DynamicRegistration: true, + }, + DidChangeWatchedFiles: &DidChangeWatchedFilesWorkspaceClientCapabilities{ + DynamicRegistration: true, + }, + Symbol: &WorkspaceSymbolClientCapabilities{ + DynamicRegistration: true, + SymbolKind: &SymbolKindCapabilities{ + ValueSet: []SymbolKind{ + SymbolKindFile, + SymbolKindModule, + SymbolKindNamespace, + SymbolKindPackage, + SymbolKindClass, + SymbolKindMethod, + }, + }, + }, + ExecuteCommand: &ExecuteCommandClientCapabilities{ + DynamicRegistration: true, + }, + WorkspaceFolders: true, + Configuration: true, + SemanticTokens: &SemanticTokensWorkspaceClientCapabilities{ + RefreshSupport: true, + }, + CodeLens: &CodeLensWorkspaceClientCapabilities{ + RefreshSupport: true, + }, + FileOperations: &WorkspaceClientCapabilitiesFileOperations{ + DynamicRegistration: true, + DidCreate: true, + WillCreate: true, + DidRename: true, + WillRename: true, + DidDelete: true, + WillDelete: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field WorkspaceClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want WorkspaceClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkspaceClientCapabilitiesWorkspaceEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentChanges":true,"failureHandling":"abort","resourceOperations":["create"],"normalizesLineEndings":true,"changeAnnotationSupport":{"groupsOnLabel":true}}` + wantNil = `{}` + ) + wantType := WorkspaceClientCapabilitiesWorkspaceEdit{ + DocumentChanges: true, + FailureHandling: string(FailureHandlingKindAbort), + ResourceOperations: []string{ + "create", + }, + NormalizesLineEndings: true, + ChangeAnnotationSupport: &WorkspaceClientCapabilitiesWorkspaceEditChangeAnnotationSupport{ + GroupsOnLabel: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field WorkspaceClientCapabilitiesWorkspaceEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: WorkspaceClientCapabilitiesWorkspaceEdit{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want WorkspaceClientCapabilitiesWorkspaceEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: WorkspaceClientCapabilitiesWorkspaceEdit{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceClientCapabilitiesWorkspaceEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["plaintext","markdown"],"deprecatedSupport":true,"preselectSupport":true},"completionItemKind":{"valueSet":[1]},"contextSupport":true},"hover":{"dynamicRegistration":true,"contentFormat":["plaintext","markdown"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["plaintext","markdown"]}},"declaration":{"dynamicRegistration":true,"linkSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6]},"hierarchicalDocumentSymbolSupport":true},"codeAction":{"dynamicRegistration":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"documentLink":{"dynamicRegistration":true},"colorProvider":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"publishDiagnostics":{"relatedInformation":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5,"lineFoldingOnly":true},"selectionRange":{"dynamicRegistration":true},"callHierarchy":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"requests":{"range":true,"full":true},"tokenTypes":["test","tokenTypes"],"tokenModifiers":["test","tokenModifiers"],"formats":["relative"],"overlappingTokenSupport":true,"multilineTokenSupport":true},"linkedEditingRange":{"dynamicRegistration":true},"moniker":{"dynamicRegistration":true}}` + wantNil = `{}` + ) + wantType := TextDocumentClientCapabilities{ + Synchronization: &TextDocumentSyncClientCapabilities{ + DynamicRegistration: true, + WillSave: true, + WillSaveWaitUntil: true, + DidSave: true, + }, + Completion: &CompletionTextDocumentClientCapabilities{ + DynamicRegistration: true, + CompletionItem: &CompletionTextDocumentClientCapabilitiesItem{ + SnippetSupport: true, + CommitCharactersSupport: true, + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + DeprecatedSupport: true, + PreselectSupport: true, + }, + CompletionItemKind: &CompletionTextDocumentClientCapabilitiesItemKind{ + ValueSet: []CompletionItemKind{CompletionItemKindText}, + }, + ContextSupport: true, + }, + Hover: &HoverTextDocumentClientCapabilities{ + DynamicRegistration: true, + ContentFormat: []MarkupKind{ + PlainText, + Markdown, + }, + }, + SignatureHelp: &SignatureHelpTextDocumentClientCapabilities{ + DynamicRegistration: true, + SignatureInformation: &TextDocumentClientCapabilitiesSignatureInformation{ + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + }, + }, + Declaration: &DeclarationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + Definition: &DefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + TypeDefinition: &TypeDefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + Implementation: &ImplementationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + }, + References: &ReferencesTextDocumentClientCapabilities{ + DynamicRegistration: true, + }, + DocumentHighlight: &DocumentHighlightClientCapabilities{ + DynamicRegistration: true, + }, + DocumentSymbol: &DocumentSymbolClientCapabilities{ + DynamicRegistration: true, + SymbolKind: &SymbolKindCapabilities{ + ValueSet: []SymbolKind{ + SymbolKindFile, + SymbolKindModule, + SymbolKindNamespace, + SymbolKindPackage, + SymbolKindClass, + SymbolKindMethod, + }, + }, + HierarchicalDocumentSymbolSupport: true, + }, + CodeAction: &CodeActionClientCapabilities{ + DynamicRegistration: true, + CodeActionLiteralSupport: &CodeActionClientCapabilitiesLiteralSupport{ + CodeActionKind: &CodeActionClientCapabilitiesKind{ + ValueSet: []CodeActionKind{ + QuickFix, + Refactor, + RefactorExtract, + RefactorRewrite, + Source, + SourceOrganizeImports, + }, + }, + }, + }, + CodeLens: &CodeLensClientCapabilities{ + DynamicRegistration: true, + }, + DocumentLink: &DocumentLinkClientCapabilities{ + DynamicRegistration: true, + }, + ColorProvider: &DocumentColorClientCapabilities{ + DynamicRegistration: true, + }, + Formatting: &DocumentFormattingClientCapabilities{ + DynamicRegistration: true, + }, + RangeFormatting: &DocumentRangeFormattingClientCapabilities{ + DynamicRegistration: true, + }, + OnTypeFormatting: &DocumentOnTypeFormattingClientCapabilities{ + DynamicRegistration: true, + }, + PublishDiagnostics: &PublishDiagnosticsClientCapabilities{ + RelatedInformation: true, + }, + Rename: &RenameClientCapabilities{ + DynamicRegistration: true, + PrepareSupport: true, + }, + FoldingRange: &FoldingRangeClientCapabilities{ + DynamicRegistration: true, + RangeLimit: uint32(5), + LineFoldingOnly: true, + }, + SelectionRange: &SelectionRangeClientCapabilities{ + DynamicRegistration: true, + }, + CallHierarchy: &CallHierarchyClientCapabilities{ + DynamicRegistration: true, + }, + SemanticTokens: &SemanticTokensClientCapabilities{ + DynamicRegistration: true, + Requests: SemanticTokensWorkspaceClientCapabilitiesRequests{ + Range: true, + Full: true, + }, + TokenTypes: []string{"test", "tokenTypes"}, + TokenModifiers: []string{"test", "tokenModifiers"}, + Formats: []TokenFormat{ + TokenFormatRelative, + }, + OverlappingTokenSupport: true, + MultilineTokenSupport: true, + }, + LinkedEditingRange: &LinkedEditingRangeClientCapabilities{ + DynamicRegistration: true, + }, + Moniker: &MonikerClientCapabilities{ + DynamicRegistration: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: TextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: TextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentSyncClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true}` + wantNil = `{}` + ) + wantType := TextDocumentSyncClientCapabilities{ + DynamicRegistration: true, + WillSave: true, + WillSaveWaitUntil: true, + DidSave: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentSyncClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: TextDocumentSyncClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentSyncClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: TextDocumentSyncClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentSyncClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCompletionTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["plaintext","markdown"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true,"resolveSupport":{"properties":["test","properties"]},"insertTextModeSupport":{"valueSet":[1,2]}},"completionItemKind":{"valueSet":[1]},"contextSupport":true}` + wantNil = `{}` + ) + wantType := CompletionTextDocumentClientCapabilities{ + DynamicRegistration: true, + CompletionItem: &CompletionTextDocumentClientCapabilitiesItem{ + SnippetSupport: true, + CommitCharactersSupport: true, + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + DeprecatedSupport: true, + PreselectSupport: true, + TagSupport: &CompletionTextDocumentClientCapabilitiesItemTagSupport{ + ValueSet: []CompletionItemTag{ + CompletionItemTagDeprecated, + }, + }, + InsertReplaceSupport: true, + ResolveSupport: &CompletionTextDocumentClientCapabilitiesItemResolveSupport{ + Properties: []string{"test", "properties"}, + }, + InsertTextModeSupport: &CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport{ + ValueSet: []InsertTextMode{ + InsertTextModeAsIs, + InsertTextModeAdjustIndentation, + }, + }, + }, + CompletionItemKind: &CompletionTextDocumentClientCapabilitiesItemKind{ + ValueSet: []CompletionItemKind{CompletionItemKindText}, + }, + ContextSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CompletionTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: CompletionTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CompletionTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: CompletionTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestHoverTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"contentFormat":["plaintext","markdown"]}` + wantNil = `{}` + ) + wantType := HoverTextDocumentClientCapabilities{ + DynamicRegistration: true, + ContentFormat: []MarkupKind{ + PlainText, + Markdown, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field HoverTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: HoverTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want HoverTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: HoverTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got HoverTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSignatureHelpTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["plaintext","markdown"],"parameterInformation":{"labelOffsetSupport":true},"activeParameterSupport":true},"contextSupport":true}` + wantNil = `{}` + ) + wantType := SignatureHelpTextDocumentClientCapabilities{ + DynamicRegistration: true, + SignatureInformation: &TextDocumentClientCapabilitiesSignatureInformation{ + DocumentationFormat: []MarkupKind{ + PlainText, + Markdown, + }, + ParameterInformation: &TextDocumentClientCapabilitiesParameterInformation{ + LabelOffsetSupport: true, + }, + ActiveParameterSupport: true, + }, + ContextSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field SignatureHelpTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: SignatureHelpTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want SignatureHelpTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: SignatureHelpTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SignatureHelpTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeclarationTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"linkSupport":true}` + wantNil = `{}` + ) + wantType := DeclarationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeclarationTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DeclarationTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeclarationTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DeclarationTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeclarationTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDefinitionTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"linkSupport":true}` + wantNil = `{}` + ) + wantType := DefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DefinitionTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DefinitionTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DefinitionTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DefinitionTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DefinitionTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTypeDefinitionTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"linkSupport":true}` + wantNil = `{}` + ) + wantType := TypeDefinitionTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TypeDefinitionTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: TypeDefinitionTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TypeDefinitionTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: TypeDefinitionTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TypeDefinitionTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestImplementationTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"linkSupport":true}` + wantNil = `{}` + ) + wantType := ImplementationTextDocumentClientCapabilities{ + DynamicRegistration: true, + LinkSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ImplementationTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: ImplementationTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ImplementationTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: ImplementationTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ImplementationTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestReferencesTextDocumentClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true}` + wantNil = `{}` + ) + wantType := ReferencesTextDocumentClientCapabilities{ + DynamicRegistration: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ReferencesTextDocumentClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: ReferencesTextDocumentClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ReferencesTextDocumentClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: ReferencesTextDocumentClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ReferencesTextDocumentClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentHighlightClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true}` + wantNil = `{}` + ) + wantType := DocumentHighlightClientCapabilities{ + DynamicRegistration: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentHighlightClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentHighlightClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentHighlightClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentHighlightClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentHighlightClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentSymbolClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]},"labelSupport":true}` + wantNil = `{}` + ) + wantType := DocumentSymbolClientCapabilities{ + DynamicRegistration: true, + SymbolKind: &SymbolKindCapabilities{ + ValueSet: []SymbolKind{ + SymbolKindFile, + SymbolKindModule, + SymbolKindNamespace, + SymbolKindPackage, + SymbolKindClass, + SymbolKindMethod, + }, + }, + HierarchicalDocumentSymbolSupport: true, + TagSupport: &DocumentSymbolClientCapabilitiesTagSupport{ + ValueSet: []SymbolTag{ + SymbolTagDeprecated, + }, + }, + LabelSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentSymbolClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentSymbolClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentSymbolClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentSymbolClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentSymbolClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeActionClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.rewrite","source","source.organizeImports"]}},"isPreferredSupport":true,"disabledSupport":true,"dataSupport":true,"resolveSupport":{"properties":["testProperties"]},"honorsChangeAnnotations":true}` + wantNil = `{}` + ) + wantType := CodeActionClientCapabilities{ + DynamicRegistration: true, + CodeActionLiteralSupport: &CodeActionClientCapabilitiesLiteralSupport{ + CodeActionKind: &CodeActionClientCapabilitiesKind{ + ValueSet: []CodeActionKind{ + QuickFix, + Refactor, + RefactorExtract, + RefactorRewrite, + Source, + SourceOrganizeImports, + }, + }, + }, + IsPreferredSupport: true, + DisabledSupport: true, + DataSupport: true, + ResolveSupport: &CodeActionClientCapabilitiesResolveSupport{ + Properties: []string{"testProperties"}, + }, + HonorsChangeAnnotations: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CodeActionClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: CodeActionClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CodeActionClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: CodeActionClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeActionClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeLensClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true}` + wantNil = `{}` + ) + wantType := CodeLensClientCapabilities{ + DynamicRegistration: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CodeLensClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: CodeLensClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CodeLensClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: CodeLensClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeLensClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentLinkClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"tooltipSupport":true}` + wantNil = `{}` + ) + wantType := DocumentLinkClientCapabilities{ + DynamicRegistration: true, + TooltipSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentLinkClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentLinkClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentLinkClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentLinkClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentLinkClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentColorClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true}` + wantNil = `{}` + ) + wantType := DocumentColorClientCapabilities{ + DynamicRegistration: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentColorClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentColorClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentColorClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentColorClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentColorClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestPublishDiagnosticsClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"relatedInformation":true,"tagSupport":{"valueSet":[2,1]},"versionSupport":true,"codeDescriptionSupport":true,"dataSupport":true}` + wantNil = `{}` + ) + wantType := PublishDiagnosticsClientCapabilities{ + RelatedInformation: true, + TagSupport: &PublishDiagnosticsClientCapabilitiesTagSupport{ + ValueSet: []DiagnosticTag{ + DiagnosticTagDeprecated, + DiagnosticTagUnnecessary, + }, + }, + VersionSupport: true, + CodeDescriptionSupport: true, + DataSupport: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field PublishDiagnosticsClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: PublishDiagnosticsClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want PublishDiagnosticsClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: PublishDiagnosticsClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got PublishDiagnosticsClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"prepareSupport":true,"prepareSupportDefaultBehavior":1,"honorsChangeAnnotations":true}` + wantNil = `{}` + ) + wantType := RenameClientCapabilities{ + DynamicRegistration: true, + PrepareSupport: true, + PrepareSupportDefaultBehavior: PrepareSupportDefaultBehaviorIdentifier, + HonorsChangeAnnotations: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field RenameClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: RenameClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want RenameClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: RenameClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestFoldingRangeClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"rangeLimit":5,"lineFoldingOnly":true}` + wantNil = `{}` + ) + wantType := FoldingRangeClientCapabilities{ + DynamicRegistration: true, + RangeLimit: uint32(5), + LineFoldingOnly: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field FoldingRangeClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: FoldingRangeClientCapabilities{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want FoldingRangeClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: FoldingRangeClientCapabilities{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FoldingRangeClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSemanticTokensClientCapabilities(t *testing.T) { + t.Parallel() + + const ( + want = `{"dynamicRegistration":true,"requests":{"range":true,"full":true},"tokenTypes":["namespace","type","class"],"tokenModifiers":["declaration","definition","readonly"],"formats":["relative"],"overlappingTokenSupport":true,"multilineTokenSupport":true}` + wantNil = `{"requests":{},"tokenTypes":["namespace","type","class"],"tokenModifiers":["declaration","definition","readonly"],"formats":["relative"]}` + ) + wantType := SemanticTokensClientCapabilities{ + DynamicRegistration: true, + Requests: SemanticTokensWorkspaceClientCapabilitiesRequests{ + Range: true, + Full: true, + }, + TokenTypes: []string{ + string(SemanticTokenNamespace), + string(SemanticTokenType), + string(SemanticTokenClass), + }, + TokenModifiers: []string{ + string(SemanticTokenModifierDeclaration), + string(SemanticTokenModifierDefinition), + string(SemanticTokenModifierReadonly), + }, + Formats: []TokenFormat{ + TokenFormatRelative, + }, + OverlappingTokenSupport: true, + MultilineTokenSupport: true, + } + wantTypeNil := SemanticTokensClientCapabilities{ + Requests: SemanticTokensWorkspaceClientCapabilitiesRequests{}, + TokenTypes: []string{ + string(SemanticTokenNamespace), + string(SemanticTokenType), + string(SemanticTokenClass), + }, + TokenModifiers: []string{ + string(SemanticTokenModifierDeclaration), + string(SemanticTokenModifierDefinition), + string(SemanticTokenModifierReadonly), + }, + Formats: []TokenFormat{ + TokenFormatRelative, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field SemanticTokensClientCapabilities + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want SemanticTokensClientCapabilities + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SemanticTokensClientCapabilities + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/capabilities_server.go b/templ/lsp/protocol/capabilities_server.go new file mode 100644 index 0000000..1a8dc05 --- /dev/null +++ b/templ/lsp/protocol/capabilities_server.go @@ -0,0 +1,523 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "strconv" +) + +// ServerCapabilities efines the capabilities provided by a language server. +type ServerCapabilities struct { + // TextDocumentSync defines how text documents are synced. Is either a detailed structure defining each notification + // or for backwards compatibility the TextDocumentSyncKind number. + // + // If omitted it defaults to TextDocumentSyncKind.None` + TextDocumentSync any `json:"textDocumentSync,omitempty"` // *TextDocumentSyncOptions | TextDocumentSyncKind + + // CompletionProvider is The server provides completion support. + CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"` + + // HoverProvider is the server provides hover support. + HoverProvider any `json:"hoverProvider,omitempty"` // TODO(zchee): bool | *HoverOptions + + // SignatureHelpProvider is the server provides signature help support. + SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"` + + // DeclarationProvider is the server provides Goto Declaration support. + // + // @since 3.14.0. + DeclarationProvider any `json:"declarationProvider,omitempty"` // TODO(zchee): bool | *DeclarationOptions | *DeclarationRegistrationOptions + + // DefinitionProvider is the server provides Goto definition support. + DefinitionProvider any `json:"definitionProvider,omitempty"` // TODO(zchee): bool | *DefinitionOptions + + // TypeDefinitionProvider is the provides Goto Type Definition support. + // + // @since 3.6.0. + TypeDefinitionProvider any `json:"typeDefinitionProvider,omitempty"` // TODO(zchee): bool | *TypeDefinitionOptions | *TypeDefinitionRegistrationOptions + + // ImplementationProvider is the provides Goto Implementation support. + // + // @since 3.6.0. + ImplementationProvider any `json:"implementationProvider,omitempty"` // TODO(zchee): bool | *ImplementationOptions | *ImplementationRegistrationOptions + + // ReferencesProvider is the server provides find references support. + ReferencesProvider any `json:"referencesProvider,omitempty"` // TODO(zchee): bool | *ReferenceOptions + + // DocumentHighlightProvider is the server provides document highlight support. + DocumentHighlightProvider any `json:"documentHighlightProvider,omitempty"` // TODO(zchee): bool | *DocumentHighlightOptions + + // DocumentSymbolProvider is the server provides document symbol support. + DocumentSymbolProvider any `json:"documentSymbolProvider,omitempty"` // TODO(zchee): bool | *DocumentSymbolOptions + + // CodeActionProvider is the server provides code actions. + // + // CodeActionOptions may only be specified if the client states that it supports CodeActionLiteralSupport in its + // initial Initialize request. + CodeActionProvider any `json:"codeActionProvider,omitempty"` // TODO(zchee): bool | *CodeActionOptions + + // CodeLensProvider is the server provides code lens. + CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"` + + // The server provides document link support. + DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"` + + // ColorProvider is the server provides color provider support. + // + // @since 3.6.0. + ColorProvider any `json:"colorProvider,omitempty"` // TODO(zchee): bool | *DocumentColorOptions | *DocumentColorRegistrationOptions + + // WorkspaceSymbolProvider is the server provides workspace symbol support. + WorkspaceSymbolProvider any `json:"workspaceSymbolProvider,omitempty"` // TODO(zchee): bool | *WorkspaceSymbolOptions + + // DocumentFormattingProvider is the server provides document formatting. + DocumentFormattingProvider any `json:"documentFormattingProvider,omitempty"` // TODO(zchee): bool | *DocumentFormattingOptions + + // DocumentRangeFormattingProvider is the server provides document range formatting. + DocumentRangeFormattingProvider any `json:"documentRangeFormattingProvider,omitempty"` // TODO(zchee): bool | *DocumentRangeFormattingOptions + + // DocumentOnTypeFormattingProvider is the server provides document formatting on typing. + DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"` + + // RenameProvider is the server provides rename support. + // + // RenameOptions may only be specified if the client states that it supports PrepareSupport in its + // initial Initialize request. + RenameProvider any `json:"renameProvider,omitempty"` // TODO(zchee): bool | *RenameOptions + + // FoldingRangeProvider is the server provides folding provider support. + // + // @since 3.10.0. + FoldingRangeProvider any `json:"foldingRangeProvider,omitempty"` // TODO(zchee): bool | *FoldingRangeOptions | *FoldingRangeRegistrationOptions + + // SelectionRangeProvider is the server provides selection range support. + // + // @since 3.15.0. + SelectionRangeProvider any `json:"selectionRangeProvider,omitempty"` // TODO(zchee): bool | *SelectionRangeOptions | *SelectionRangeRegistrationOptions + + // ExecuteCommandProvider is the server provides execute command support. + ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"` + + // CallHierarchyProvider is the server provides call hierarchy support. + // + // @since 3.16.0. + CallHierarchyProvider any `json:"callHierarchyProvider,omitempty"` // TODO(zchee): bool | *CallHierarchyOptions | *CallHierarchyRegistrationOptions + + // LinkedEditingRangeProvider is the server provides linked editing range support. + // + // @since 3.16.0. + LinkedEditingRangeProvider any `json:"linkedEditingRangeProvider,omitempty"` // TODO(zchee): bool | *LinkedEditingRangeOptions | *LinkedEditingRangeRegistrationOptions + + // SemanticTokensProvider is the server provides semantic tokens support. + // + // @since 3.16.0. + SemanticTokensProvider any `json:"semanticTokensProvider,omitempty"` // TODO(zchee): *SemanticTokensOptions | *SemanticTokensRegistrationOptions + + // Workspace is the window specific server capabilities. + Workspace *ServerCapabilitiesWorkspace `json:"workspace,omitempty"` + + // MonikerProvider is the server provides moniker support. + // + // @since 3.16.0. + MonikerProvider any `json:"monikerProvider,omitempty"` // TODO(zchee): bool | *MonikerOptions | *MonikerRegistrationOptions + + // Experimental server capabilities. + Experimental any `json:"experimental,omitempty"` +} + +// TextDocumentSyncOptions TextDocumentSync options. +type TextDocumentSyncOptions struct { + // OpenClose open and close notifications are sent to the server. + OpenClose bool `json:"openClose,omitempty"` + + // Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + // and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None. + Change TextDocumentSyncKind `json:"change,omitempty"` + + // WillSave notifications are sent to the server. + WillSave bool `json:"willSave,omitempty"` + + // WillSaveWaitUntil will save wait until requests are sent to the server. + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + + // Save notifications are sent to the server. + Save *SaveOptions `json:"save,omitempty"` +} + +// SaveOptions save options. +type SaveOptions struct { + // IncludeText is the client is supposed to include the content on save. + IncludeText bool `json:"includeText,omitempty"` +} + +// TextDocumentSyncKind defines how the host (editor) should sync document changes to the language server. +type TextDocumentSyncKind float64 + +const ( + // TextDocumentSyncKindNone documents should not be synced at all. + TextDocumentSyncKindNone TextDocumentSyncKind = 0 + + // TextDocumentSyncKindFull documents are synced by always sending the full content + // of the document. + TextDocumentSyncKindFull TextDocumentSyncKind = 1 + + // TextDocumentSyncKindIncremental documents are synced by sending the full content on open. + // After that only incremental updates to the document are + // send. + TextDocumentSyncKindIncremental TextDocumentSyncKind = 2 +) + +// String implements fmt.Stringer. +func (k TextDocumentSyncKind) String() string { + switch k { + case TextDocumentSyncKindNone: + return "None" + case TextDocumentSyncKindFull: + return "Full" + case TextDocumentSyncKindIncremental: + return "Incremental" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// CompletionOptions Completion options. +type CompletionOptions struct { + // The server provides support to resolve additional + // information for a completion item. + ResolveProvider bool `json:"resolveProvider,omitempty"` + + // The characters that trigger completion automatically. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` +} + +// HoverOptions option of hover provider server capabilities. +type HoverOptions struct { + WorkDoneProgressOptions +} + +// SignatureHelpOptions SignatureHelp options. +type SignatureHelpOptions struct { + // The characters that trigger signature help + // automatically. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + // RetriggerCharacters is the slist of characters that re-trigger signature help. + // + // These trigger characters are only active when signature help is already + // showing. + // All trigger characters are also counted as re-trigger characters. + // + // @since 3.15.0. + RetriggerCharacters []string `json:"retriggerCharacters,omitempty"` +} + +// DeclarationOptions registration option of Declaration server capability. +// +// @since 3.15.0. +type DeclarationOptions struct { + WorkDoneProgressOptions +} + +// DeclarationRegistrationOptions registration option of Declaration server capability. +// +// @since 3.15.0. +type DeclarationRegistrationOptions struct { + DeclarationOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +// DefinitionOptions registration option of Definition server capability. +// +// @since 3.15.0. +type DefinitionOptions struct { + WorkDoneProgressOptions +} + +// TypeDefinitionOptions registration option of TypeDefinition server capability. +// +// @since 3.15.0. +type TypeDefinitionOptions struct { + WorkDoneProgressOptions +} + +// TypeDefinitionRegistrationOptions registration option of TypeDefinition server capability. +// +// @since 3.15.0. +type TypeDefinitionRegistrationOptions struct { + TextDocumentRegistrationOptions + TypeDefinitionOptions + StaticRegistrationOptions +} + +// ImplementationOptions registration option of Implementation server capability. +// +// @since 3.15.0. +type ImplementationOptions struct { + WorkDoneProgressOptions +} + +// ImplementationRegistrationOptions registration option of Implementation server capability. +// +// @since 3.15.0. +type ImplementationRegistrationOptions struct { + TextDocumentRegistrationOptions + ImplementationOptions + StaticRegistrationOptions +} + +// ReferenceOptions registration option of Reference server capability. +type ReferenceOptions struct { + WorkDoneProgressOptions +} + +// DocumentHighlightOptions registration option of DocumentHighlight server capability. +// +// @since 3.15.0. +type DocumentHighlightOptions struct { + WorkDoneProgressOptions +} + +// DocumentSymbolOptions registration option of DocumentSymbol server capability. +// +// @since 3.15.0. +type DocumentSymbolOptions struct { + WorkDoneProgressOptions + + // Label a human-readable string that is shown when multiple outlines trees + // are shown for the same document. + // + // @since 3.16.0. + Label string `json:"label,omitempty"` +} + +// CodeActionOptions CodeAction options. +type CodeActionOptions struct { + // CodeActionKinds that this server may return. + // + // The list of kinds may be generic, such as "CodeActionKind.Refactor", or the server + // may list out every specific kind they provide. + CodeActionKinds []CodeActionKind `json:"codeActionKinds,omitempty"` + + // ResolveProvider is the server provides support to resolve additional + // information for a code action. + // + // @since 3.16.0. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// CodeLensOptions CodeLens options. +type CodeLensOptions struct { + // Code lens has a resolve provider as well. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// DocumentLinkOptions document link options. +type DocumentLinkOptions struct { + // ResolveProvider document links have a resolve provider as well. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// DocumentColorOptions registration option of DocumentColor server capability. +// +// @since 3.15.0. +type DocumentColorOptions struct { + WorkDoneProgressOptions +} + +// DocumentColorRegistrationOptions registration option of DocumentColor server capability. +// +// @since 3.15.0. +type DocumentColorRegistrationOptions struct { + TextDocumentRegistrationOptions + StaticRegistrationOptions + DocumentColorOptions +} + +// WorkspaceSymbolOptions registration option of WorkspaceSymbol server capability. +// +// @since 3.15.0. +type WorkspaceSymbolOptions struct { + WorkDoneProgressOptions +} + +// DocumentFormattingOptions registration option of DocumentFormatting server capability. +// +// @since 3.15.0. +type DocumentFormattingOptions struct { + WorkDoneProgressOptions +} + +// DocumentRangeFormattingOptions registration option of DocumentRangeFormatting server capability. +// +// @since 3.15.0. +type DocumentRangeFormattingOptions struct { + WorkDoneProgressOptions +} + +// DocumentOnTypeFormattingOptions format document on type options. +type DocumentOnTypeFormattingOptions struct { + // FirstTriggerCharacter a character on which formatting should be triggered, like "}". + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + + // MoreTriggerCharacter more trigger characters. + MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"` +} + +// RenameOptions rename options. +type RenameOptions struct { + // PrepareProvider renames should be checked and tested before being executed. + PrepareProvider bool `json:"prepareProvider,omitempty"` +} + +// FoldingRangeOptions registration option of FoldingRange server capability. +// +// @since 3.15.0. +type FoldingRangeOptions struct { + WorkDoneProgressOptions +} + +// FoldingRangeRegistrationOptions registration option of FoldingRange server capability. +// +// @since 3.15.0. +type FoldingRangeRegistrationOptions struct { + TextDocumentRegistrationOptions + FoldingRangeOptions + StaticRegistrationOptions +} + +// ExecuteCommandOptions execute command options. +type ExecuteCommandOptions struct { + // Commands is the commands to be executed on the server + Commands []string `json:"commands"` +} + +// CallHierarchyOptions option of CallHierarchy. +// +// @since 3.16.0. +type CallHierarchyOptions struct { + WorkDoneProgressOptions +} + +// CallHierarchyRegistrationOptions registration options of CallHierarchy. +// +// @since 3.16.0. +type CallHierarchyRegistrationOptions struct { + TextDocumentRegistrationOptions + CallHierarchyOptions + StaticRegistrationOptions +} + +// LinkedEditingRangeOptions option of linked editing range provider server capabilities. +// +// @since 3.16.0. +type LinkedEditingRangeOptions struct { + WorkDoneProgressOptions +} + +// LinkedEditingRangeRegistrationOptions registration option of linked editing range provider server capabilities. +// +// @since 3.16.0. +type LinkedEditingRangeRegistrationOptions struct { + TextDocumentRegistrationOptions + LinkedEditingRangeOptions + StaticRegistrationOptions +} + +// SemanticTokensOptions option of semantic tokens provider server capabilities. +// +// @since 3.16.0. +type SemanticTokensOptions struct { + WorkDoneProgressOptions +} + +// SemanticTokensRegistrationOptions registration option of semantic tokens provider server capabilities. +// +// @since 3.16.0. +type SemanticTokensRegistrationOptions struct { + TextDocumentRegistrationOptions + SemanticTokensOptions + StaticRegistrationOptions +} + +// ServerCapabilitiesWorkspace specific server capabilities. +type ServerCapabilitiesWorkspace struct { + // WorkspaceFolders is the server supports workspace folder. + // + // @since 3.6.0. + WorkspaceFolders *ServerCapabilitiesWorkspaceFolders `json:"workspaceFolders,omitempty"` + + // FileOperations is the server is interested in file notifications/requests. + // + // @since 3.16.0. + FileOperations *ServerCapabilitiesWorkspaceFileOperations `json:"fileOperations,omitempty"` +} + +// ServerCapabilitiesWorkspaceFolders is the server supports workspace folder. +// +// @since 3.6.0. +type ServerCapabilitiesWorkspaceFolders struct { + // Supported is the server has support for workspace folders + Supported bool `json:"supported,omitempty"` + + // ChangeNotifications whether the server wants to receive workspace folder + // change notifications. + // + // If a strings is provided the string is treated as a ID + // under which the notification is registered on the client + // side. The ID can be used to unregister for these events + // using the `client/unregisterCapability` request. + ChangeNotifications any `json:"changeNotifications,omitempty"` // string | boolean +} + +// ServerCapabilitiesWorkspaceFileOperations is the server is interested in file notifications/requests. +// +// @since 3.16.0. +type ServerCapabilitiesWorkspaceFileOperations struct { + // DidCreate is the server is interested in receiving didCreateFiles + // notifications. + DidCreate *FileOperationRegistrationOptions `json:"didCreate,omitempty"` + + // WillCreate is the server is interested in receiving willCreateFiles requests. + WillCreate *FileOperationRegistrationOptions `json:"willCreate,omitempty"` + + // DidRename is the server is interested in receiving didRenameFiles + // notifications. + DidRename *FileOperationRegistrationOptions `json:"didRename,omitempty"` + + // WillRename is the server is interested in receiving willRenameFiles requests. + WillRename *FileOperationRegistrationOptions `json:"willRename,omitempty"` + + // DidDelete is the server is interested in receiving didDeleteFiles file + // notifications. + DidDelete *FileOperationRegistrationOptions `json:"didDelete,omitempty"` + + // WillDelete is the server is interested in receiving willDeleteFiles file + // requests. + WillDelete *FileOperationRegistrationOptions `json:"willDelete,omitempty"` +} + +// FileOperationRegistrationOptions is the options to register for file operations. +// +// @since 3.16.0. +type FileOperationRegistrationOptions struct { + // filters is the actual filters. + Filters []FileOperationFilter `json:"filters"` +} + +// MonikerOptions option of moniker provider server capabilities. +// +// @since 3.16.0. +type MonikerOptions struct { + WorkDoneProgressOptions +} + +// MonikerRegistrationOptions registration option of moniker provider server capabilities. +// +// @since 3.16.0. +type MonikerRegistrationOptions struct { + TextDocumentRegistrationOptions + MonikerOptions +} diff --git a/templ/lsp/protocol/client.go b/templ/lsp/protocol/client.go new file mode 100644 index 0000000..378ba34 --- /dev/null +++ b/templ/lsp/protocol/client.go @@ -0,0 +1,412 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "bytes" + "context" + "fmt" + "log/slog" + + "encoding/json" + + "github.com/a-h/templ/lsp/jsonrpc2" + "github.com/a-h/templ/lsp/xcontext" +) + +// ClientDispatcher returns a Client that dispatches LSP requests across the +// given jsonrpc2 connection. +func ClientDispatcher(conn jsonrpc2.Conn, logger *slog.Logger) Client { + return &client{ + Conn: conn, + logger: logger, + } +} + +// ClientHandler handler of LSP client. +func ClientHandler(log *slog.Logger, client Client, handler jsonrpc2.Handler) jsonrpc2.Handler { + h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { + if ctx.Err() != nil { + xctx := xcontext.Detach(ctx) + + return reply(xctx, nil, ErrRequestCancelled) + } + + handled, err := clientDispatch(ctx, log, client, reply, req) + if handled || err != nil { + return err + } + + return handler(ctx, reply, req) + } + + return h +} + +// clientDispatch implements jsonrpc2.Handler. +// +//nolint:funlen,cyclop +func clientDispatch(ctx context.Context, log *slog.Logger, client Client, reply jsonrpc2.Replier, req jsonrpc2.Request) (handled bool, err error) { + if ctx.Err() != nil { + return true, reply(ctx, nil, ErrRequestCancelled) + } + + dec := json.NewDecoder(bytes.NewReader(req.Params())) + + switch req.Method() { + case MethodProgress: // notification + defer log.Debug(MethodProgress, slog.Any("error", err)) + + var params ProgressParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.Progress(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWorkDoneProgressCreate: // request + defer log.Debug(MethodWorkDoneProgressCreate, slog.Any("error", err)) + + var params WorkDoneProgressCreateParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.WorkDoneProgressCreate(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWindowLogMessage: // notification + defer log.Debug(MethodWindowLogMessage, slog.Any("error", err)) + + var params LogMessageParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.LogMessage(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentPublishDiagnostics: // notification + defer log.Debug(MethodTextDocumentPublishDiagnostics, slog.Any("error", err)) + + var params PublishDiagnosticsParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.PublishDiagnostics(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWindowShowMessage: // notification + defer log.Debug(MethodWindowShowMessage, slog.Any("error", err)) + + var params ShowMessageParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.ShowMessage(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWindowShowMessageRequest: // request + defer log.Debug(MethodWindowShowMessageRequest, slog.Any("error", err)) + + var params ShowMessageRequestParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := client.ShowMessageRequest(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTelemetryEvent: // notification + defer log.Debug(MethodTelemetryEvent, slog.Any("error", err)) + + var params any + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.Telemetry(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodClientRegisterCapability: // request + defer log.Debug(MethodClientRegisterCapability, slog.Any("error", err)) + + var params RegistrationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.RegisterCapability(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodClientUnregisterCapability: // request + defer log.Debug(MethodClientUnregisterCapability, slog.Any("error", err)) + + var params UnregistrationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := client.UnregisterCapability(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWorkspaceApplyEdit: // request + defer log.Debug(MethodWorkspaceApplyEdit, slog.Any("error", err)) + + var params ApplyWorkspaceEditParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := client.ApplyEdit(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodWorkspaceConfiguration: // request + defer log.Debug(MethodWorkspaceConfiguration, slog.Any("error", err)) + + var params ConfigurationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := client.Configuration(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodWorkspaceWorkspaceFolders: // request + defer log.Debug(MethodWorkspaceWorkspaceFolders, slog.Any("error", err)) + + if len(req.Params()) > 0 { + return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + + resp, err := client.WorkspaceFolders(ctx) + + return true, reply(ctx, resp, err) + + default: + return false, nil + } +} + +// Client represents a Language Server Protocol client. +type Client interface { + Progress(ctx context.Context, params *ProgressParams) (err error) + WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error) + LogMessage(ctx context.Context, params *LogMessageParams) (err error) + PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error) + ShowMessage(ctx context.Context, params *ShowMessageParams) (err error) + ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (result *MessageActionItem, err error) + Telemetry(ctx context.Context, params any) (err error) + RegisterCapability(ctx context.Context, params *RegistrationParams) (err error) + UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error) + ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error) + Configuration(ctx context.Context, params *ConfigurationParams) (result []any, err error) + WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error) +} + +// list of client methods. +const ( + // MethodProgress method name of "$/progress". + MethodProgress = "$/progress" + + // MethodWorkDoneProgressCreate method name of "window/workDoneProgress/create". + MethodWorkDoneProgressCreate = "window/workDoneProgress/create" + + // MethodWindowShowMessage method name of "window/showMessage". + MethodWindowShowMessage = "window/showMessage" + + // MethodWindowShowMessageRequest method name of "window/showMessageRequest. + MethodWindowShowMessageRequest = "window/showMessageRequest" + + // MethodWindowLogMessage method name of "window/logMessage. + MethodWindowLogMessage = "window/logMessage" + + // MethodTelemetryEvent method name of "telemetry/event. + MethodTelemetryEvent = "telemetry/event" + + // MethodClientRegisterCapability method name of "client/registerCapability. + MethodClientRegisterCapability = "client/registerCapability" + + // MethodClientUnregisterCapability method name of "client/unregisterCapability. + MethodClientUnregisterCapability = "client/unregisterCapability" + + // MethodTextDocumentPublishDiagnostics method name of "textDocument/publishDiagnostics. + MethodTextDocumentPublishDiagnostics = "textDocument/publishDiagnostics" + + // MethodWorkspaceApplyEdit method name of "workspace/applyEdit. + MethodWorkspaceApplyEdit = "workspace/applyEdit" + + // MethodWorkspaceConfiguration method name of "workspace/configuration. + MethodWorkspaceConfiguration = "workspace/configuration" + + // MethodWorkspaceWorkspaceFolders method name of "workspace/workspaceFolders". + MethodWorkspaceWorkspaceFolders = "workspace/workspaceFolders" +) + +// client implements a Language Server Protocol client. +type client struct { + jsonrpc2.Conn + + logger *slog.Logger +} + +// compiler time check whether the Client implements ClientInterface interface. +var _ Client = (*client)(nil) + +// Progress is the base protocol offers also support to report progress in a generic fashion. +// +// This mechanism can be used to report any kind of progress including work done progress (usually used to report progress in the user interface using a progress bar) and +// partial result progress to support streaming of results. +// +// @since 3.16.0. +func (c *client) Progress(ctx context.Context, params *ProgressParams) (err error) { + c.logger.Debug("call " + MethodProgress) + defer c.logger.Debug("end "+MethodProgress, slog.Any("error", err)) + + return c.Conn.Notify(ctx, MethodProgress, params) +} + +// WorkDoneProgressCreate sends the request is sent from the server to the client to ask the client to create a work done progress. +// +// @since 3.16.0. +func (c *client) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error) { + c.logger.Debug("call " + MethodWorkDoneProgressCreate) + defer c.logger.Debug("end "+MethodWorkDoneProgressCreate, slog.Any("error", err)) + + return Call(ctx, c.Conn, MethodWorkDoneProgressCreate, params, nil) +} + +// LogMessage sends the notification from the server to the client to ask the client to log a particular message. +func (c *client) LogMessage(ctx context.Context, params *LogMessageParams) (err error) { + c.logger.Debug("call " + MethodWindowLogMessage) + defer c.logger.Debug("end "+MethodWindowLogMessage, slog.Any("error", err)) + + return c.Conn.Notify(ctx, MethodWindowLogMessage, params) +} + +// PublishDiagnostics sends the notification from the server to the client to signal results of validation runs. +// +// Diagnostics are “owned” by the server so it is the server’s responsibility to clear them if necessary. The following rule is used for VS Code servers that generate diagnostics: +// +// - if a language is single file only (for example HTML) then diagnostics are cleared by the server when the file is closed. +// - if a language has a project system (for example C#) diagnostics are not cleared when a file closes. When a project is opened all diagnostics for all files are recomputed (or read from a cache). +// +// When a file changes it is the server’s responsibility to re-compute diagnostics and push them to the client. +// If the computed set is empty it has to push the empty array to clear former diagnostics. +// Newly pushed diagnostics always replace previously pushed diagnostics. There is no merging that happens on the client side. +func (c *client) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error) { + c.logger.Debug("call " + MethodTextDocumentPublishDiagnostics) + defer c.logger.Debug("end "+MethodTextDocumentPublishDiagnostics, slog.Any("error", err)) + + return c.Conn.Notify(ctx, MethodTextDocumentPublishDiagnostics, params) +} + +// ShowMessage sends the notification from a server to a client to ask the +// client to display a particular message in the user interface. +func (c *client) ShowMessage(ctx context.Context, params *ShowMessageParams) (err error) { + return c.Conn.Notify(ctx, MethodWindowShowMessage, params) +} + +// ShowMessageRequest sends the request from a server to a client to ask the client to display a particular message in the user interface. +// +// In addition to the show message notification the request allows to pass actions and to wait for an answer from the client. +func (c *client) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (_ *MessageActionItem, err error) { + c.logger.Debug("call " + MethodWindowShowMessageRequest) + defer c.logger.Debug("end "+MethodWindowShowMessageRequest, slog.Any("error", err)) + + var result *MessageActionItem + if err := Call(ctx, c.Conn, MethodWindowShowMessageRequest, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Telemetry sends the notification from the server to the client to ask the client to log a telemetry event. +func (c *client) Telemetry(ctx context.Context, params any) (err error) { + c.logger.Debug("call " + MethodTelemetryEvent) + defer c.logger.Debug("end "+MethodTelemetryEvent, slog.Any("error", err)) + + return c.Conn.Notify(ctx, MethodTelemetryEvent, params) +} + +// RegisterCapability sends the request from the server to the client to register for a new capability on the client side. +// +// Not all clients need to support dynamic capability registration. +// +// A client opts in via the dynamicRegistration property on the specific client capabilities. +// A client can even provide dynamic registration for capability A but not for capability B (see TextDocumentClientCapabilities as an example). +func (c *client) RegisterCapability(ctx context.Context, params *RegistrationParams) (err error) { + c.logger.Debug("call " + MethodClientRegisterCapability) + defer c.logger.Debug("end "+MethodClientRegisterCapability, slog.Any("error", err)) + + return Call(ctx, c.Conn, MethodClientRegisterCapability, params, nil) +} + +// UnregisterCapability sends the request from the server to the client to unregister a previously registered capability. +func (c *client) UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error) { + c.logger.Debug("call " + MethodClientUnregisterCapability) + defer c.logger.Debug("end "+MethodClientUnregisterCapability, slog.Any("error", err)) + + return Call(ctx, c.Conn, MethodClientUnregisterCapability, params, nil) +} + +// ApplyEdit sends the request from the server to the client to modify resource on the client side. +func (c *client) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error) { + c.logger.Debug("call " + MethodWorkspaceApplyEdit) + defer c.logger.Debug("end "+MethodWorkspaceApplyEdit, slog.Any("error", err)) + + if err := Call(ctx, c.Conn, MethodWorkspaceApplyEdit, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Configuration sends the request from the server to the client to fetch configuration settings from the client. +// +// The request can fetch several configuration settings in one roundtrip. +// The order of the returned configuration settings correspond to the order of the +// passed ConfigurationItems (e.g. the first item in the response is the result for the first configuration item in the params). +func (c *client) Configuration(ctx context.Context, params *ConfigurationParams) (_ []any, err error) { + c.logger.Debug("call " + MethodWorkspaceConfiguration) + defer c.logger.Debug("end "+MethodWorkspaceConfiguration, slog.Any("error", err)) + + var result []any + if err := Call(ctx, c.Conn, MethodWorkspaceConfiguration, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// WorkspaceFolders sends the request from the server to the client to fetch the current open list of workspace folders. +// +// Returns null in the response if only a single file is open in the tool. Returns an empty array if a workspace is open but no folders are configured. +// +// @since 3.6.0. +func (c *client) WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error) { + c.logger.Debug("call " + MethodWorkspaceWorkspaceFolders) + defer c.logger.Debug("end "+MethodWorkspaceWorkspaceFolders, slog.Any("error", err)) + + if err := Call(ctx, c.Conn, MethodWorkspaceWorkspaceFolders, nil, &result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/templ/lsp/protocol/context.go b/templ/lsp/protocol/context.go new file mode 100644 index 0000000..253f93b --- /dev/null +++ b/templ/lsp/protocol/context.go @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "context" +) + +type ctxClientKey int + +var ctxClient ctxClientKey = 0 + +// WithClient returns the context with Client value. +func WithClient(ctx context.Context, client Client) context.Context { + return context.WithValue(ctx, ctxClient, client) +} + +// ClientFromContext extracts Client from context. +func ClientFromContext(ctx context.Context) Client { + client, ok := ctx.Value(ctxClient).(Client) + if !ok { + return nil + } + return client +} diff --git a/templ/lsp/protocol/deprecated.go b/templ/lsp/protocol/deprecated.go new file mode 100644 index 0000000..fa4b216 --- /dev/null +++ b/templ/lsp/protocol/deprecated.go @@ -0,0 +1,264 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// ClientCapabilitiesShowDocument alias of ShowDocumentClientCapabilities. +// +// Deprecated: Use ShowDocumentClientCapabilities instead. +type ClientCapabilitiesShowDocument = ShowDocumentClientCapabilities + +// ClientCapabilitiesShowMessageRequest alias of ShowMessageRequestClientCapabilities. +// +// Deprecated: Use ShowMessageRequestClientCapabilities instead. +type ClientCapabilitiesShowMessageRequest = ShowMessageRequestClientCapabilities + +// ClientCapabilitiesShowMessageRequestMessageActionItem alias of ShowMessageRequestClientCapabilitiesMessageActionItem. +// +// Deprecated: Use ShowMessageRequestClientCapabilitiesMessageActionItem instead. +type ClientCapabilitiesShowMessageRequestMessageActionItem = ShowMessageRequestClientCapabilitiesMessageActionItem + +// ReferencesParams alias of ReferenceParams. +// +// Deprecated: Use ReferenceParams instead. +type ReferencesParams = ReferenceParams + +// TextDocumentClientCapabilitiesCallHierarchy alias of CallHierarchyClientCapabilities. +// +// Deprecated: Use CallHierarchyClientCapabilities instead. +type TextDocumentClientCapabilitiesCallHierarchy = CallHierarchyClientCapabilities + +// TextDocumentClientCapabilitiesCodeAction alias of CodeActionClientCapabilities. +// +// Deprecated: Use CodeActionClientCapabilities instead. +type TextDocumentClientCapabilitiesCodeAction = CodeActionClientCapabilities + +// TextDocumentClientCapabilitiesCodeActionKind alias of CodeActionClientCapabilitiesKind. +// +// Deprecated: Use CodeActionClientCapabilitiesKind instead. +type TextDocumentClientCapabilitiesCodeActionKind = CodeActionClientCapabilitiesKind + +// TextDocumentClientCapabilitiesCodeActionLiteralSupport alias of CodeActionClientCapabilitiesLiteralSupport. +// +// Deprecated: Use CodeActionClientCapabilitiesLiteralSupport instead. +type TextDocumentClientCapabilitiesCodeActionLiteralSupport = CodeActionClientCapabilitiesLiteralSupport + +// TextDocumentClientCapabilitiesCodeActionResolveSupport alias of CodeActionClientCapabilitiesResolveSupport. +// +// Deprecated: Use CodeActionClientCapabilitiesResolveSupport instead. +type TextDocumentClientCapabilitiesCodeActionResolveSupport = CodeActionClientCapabilitiesResolveSupport + +// TextDocumentClientCapabilitiesCodeLens alias of CodeLensClientCapabilities. +// +// Deprecated: Use CodeLensClientCapabilities instead. +type TextDocumentClientCapabilitiesCodeLens = CodeLensClientCapabilities + +// TextDocumentClientCapabilitiesColorProvider alias of DocumentColorClientCapabilities. +// +// Deprecated: Use DocumentColorClientCapabilities instead. +type TextDocumentClientCapabilitiesColorProvider = DocumentColorClientCapabilities + +// TextDocumentClientCapabilitiesCompletion alias of CompletionTextDocumentClientCapabilities. +// +// Deprecated: Use CompletionTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesCompletion = CompletionTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesCompletionItem alias of CompletionTextDocumentClientCapabilitiesItem. +// +// Deprecated: Use CompletionTextDocumentClientCapabilitiesItem instead. +type TextDocumentClientCapabilitiesCompletionItem = CompletionTextDocumentClientCapabilitiesItem + +// TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport alias of CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport. +// +// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport instead. +type TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport = CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport + +// TextDocumentClientCapabilitiesCompletionItemKind alias of CompletionTextDocumentClientCapabilitiesItemKind. +// +// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemKind instead. +type TextDocumentClientCapabilitiesCompletionItemKind = CompletionTextDocumentClientCapabilitiesItemKind + +// TextDocumentClientCapabilitiesCompletionItemResolveSupport alias of CompletionTextDocumentClientCapabilitiesItemResolveSupport. +// +// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemResolveSupport instead. +type TextDocumentClientCapabilitiesCompletionItemResolveSupport = CompletionTextDocumentClientCapabilitiesItemResolveSupport + +// TextDocumentClientCapabilitiesCompletionItemTagSupport alias of CompletionTextDocumentClientCapabilitiesItemTagSupport. +// +// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemTagSupport instead. +type TextDocumentClientCapabilitiesCompletionItemTagSupport = CompletionTextDocumentClientCapabilitiesItemTagSupport + +// TextDocumentClientCapabilitiesDeclaration alias of DeclarationTextDocumentClientCapabilities. +// +// Deprecated: Use DeclarationTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesDeclaration = DeclarationTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesDefinition alias of DefinitionTextDocumentClientCapabilities. +// +// Deprecated: Use DefinitionTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesDefinition = DefinitionTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesDocumentHighlight alias of DocumentHighlightClientCapabilities. +// +// Deprecated: Use DocumentHighlightClientCapabilities instead. +type TextDocumentClientCapabilitiesDocumentHighlight = DocumentHighlightClientCapabilities + +// TextDocumentClientCapabilitiesDocumentLink alias of DocumentLinkClientCapabilities. +// +// Deprecated: Use DocumentLinkClientCapabilities instead. +type TextDocumentClientCapabilitiesDocumentLink = DocumentLinkClientCapabilities + +// TextDocumentClientCapabilitiesDocumentSymbol alias of DocumentSymbolClientCapabilities. +// +// Deprecated: Use DocumentSymbolClientCapabilities instead. +type TextDocumentClientCapabilitiesDocumentSymbol = DocumentSymbolClientCapabilities + +// TextDocumentClientCapabilitiesDocumentSymbolTagSupport alias of DocumentSymbolClientCapabilitiesTagSupport. +// +// Deprecated: Use DocumentSymbolClientCapabilitiesTagSupport instead. +type TextDocumentClientCapabilitiesDocumentSymbolTagSupport = DocumentSymbolClientCapabilitiesTagSupport + +// TextDocumentClientCapabilitiesFoldingRange alias of FoldingRangeClientCapabilities. +// +// Deprecated: Use FoldingRangeClientCapabilities instead. +type TextDocumentClientCapabilitiesFoldingRange = FoldingRangeClientCapabilities + +// TextDocumentClientCapabilitiesFormatting alias of DocumentFormattingClientCapabilities. +// +// Deprecated: Use DocumentFormattingClientCapabilities instead. +type TextDocumentClientCapabilitiesFormatting = DocumentFormattingClientCapabilities + +// TextDocumentClientCapabilitiesHover alias of HoverTextDocumentClientCapabilities. +// +// Deprecated: Use HoverTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesHover = HoverTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesImplementation alias of ImplementationTextDocumentClientCapabilities. +// +// Deprecated: Use ImplementationTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesImplementation = ImplementationTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesLinkedEditingRange alias of LinkedEditingRangeClientCapabilities. +// +// Deprecated: Use LinkedEditingRangeClientCapabilities instead. +type TextDocumentClientCapabilitiesLinkedEditingRange = LinkedEditingRangeClientCapabilities + +// TextDocumentClientCapabilitiesMoniker of MonikerClientCapabilities. +// +// Deprecated: Use MonikerClientCapabilities instead. +type TextDocumentClientCapabilitiesMoniker = MonikerClientCapabilities + +// TextDocumentClientCapabilitiesOnTypeFormatting of DocumentOnTypeFormattingClientCapabilities. +// +// Deprecated: Use DocumentOnTypeFormattingClientCapabilities instead. +type TextDocumentClientCapabilitiesOnTypeFormatting = DocumentOnTypeFormattingClientCapabilities + +// TextDocumentClientCapabilitiesPublishDiagnostics of PublishDiagnosticsClientCapabilities. +// +// Deprecated: Use PublishDiagnosticsClientCapabilities instead. +type TextDocumentClientCapabilitiesPublishDiagnostics = PublishDiagnosticsClientCapabilities + +// TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport of PublishDiagnosticsClientCapabilitiesTagSupport. +// +// Deprecated: Use PublishDiagnosticsClientCapabilitiesTagSupport instead. +type TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport = PublishDiagnosticsClientCapabilitiesTagSupport + +// TextDocumentClientCapabilitiesRangeFormatting of DocumentRangeFormattingClientCapabilities. +// +// Deprecated: Use DocumentRangeFormattingClientCapabilities instead. +type TextDocumentClientCapabilitiesRangeFormatting = DocumentRangeFormattingClientCapabilities + +// TextDocumentClientCapabilitiesReferences of ReferencesTextDocumentClientCapabilities. +// +// Deprecated: Use ReferencesTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesReferences = ReferencesTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesRename of RenameClientCapabilities. +// +// Deprecated: Use RenameClientCapabilities instead. +type TextDocumentClientCapabilitiesRename = RenameClientCapabilities + +// TextDocumentClientCapabilitiesSelectionRange of SelectionRangeClientCapabilities. +// +// Deprecated: Use SelectionRangeClientCapabilities instead. +type TextDocumentClientCapabilitiesSelectionRange = SelectionRangeClientCapabilities + +// TextDocumentClientCapabilitiesSemanticTokens of SemanticTokensClientCapabilities. +// +// Deprecated: Use SemanticTokensClientCapabilities instead. +type TextDocumentClientCapabilitiesSemanticTokens = SemanticTokensClientCapabilities + +// TextDocumentClientCapabilitiesSignatureHelp of SignatureHelpTextDocumentClientCapabilities. +// +// Deprecated: Use SignatureHelpTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesSignatureHelp = SignatureHelpTextDocumentClientCapabilities + +// TextDocumentClientCapabilitiesSynchronization of TextDocumentSyncClientCapabilities. +// +// Deprecated: Use TextDocumentSyncClientCapabilities instead. +type TextDocumentClientCapabilitiesSynchronization = TextDocumentSyncClientCapabilities + +// TextDocumentClientCapabilitiesTypeDefinition of TypeDefinitionTextDocumentClientCapabilities. +// +// Deprecated: Use TypeDefinitionTextDocumentClientCapabilities instead. +type TextDocumentClientCapabilitiesTypeDefinition = TypeDefinitionTextDocumentClientCapabilities + +// Abort alias of FailureHandlingKindAbort. +// +// Deprecated: Use FailureHandlingKindAbort instead. +const Abort = FailureHandlingKindAbort + +// TextOnlyTransactional alias of FailureHandlingKindTextOnlyTransactional. +// +// Deprecated: Use FailureHandlingKindTextOnlyTransactional instead. +const TextOnlyTransactional = FailureHandlingKindTextOnlyTransactional + +// Transactional alias of FailureHandlingKindTransactional. +// +// Deprecated: Use FailureHandlingKindTransactional instead. +const Transactional = FailureHandlingKindTransactional + +// Undo alias of FailureHandlingKindUndo. +// +// Deprecated: Use FailureHandlingKindUndo instead. +const Undo = FailureHandlingKindUndo + +// WorkspaceClientCapabilitiesSymbol alias of WorkspaceSymbolClientCapabilities. +// +// Deprecated: Use WorkspaceSymbolClientCapabilities instead. +type WorkspaceClientCapabilitiesSymbol = WorkspaceSymbolClientCapabilities + +// WorkspaceClientCapabilitiesSymbolKind alias of SymbolKindCapabilities. +// +// Deprecated: Use SymbolKindCapabilities instead. +type WorkspaceClientCapabilitiesSymbolKind = SymbolKindCapabilities + +// WorkspaceClientCapabilitiesCodeLens alias of CodeLensWorkspaceClientCapabilities. +// +// Deprecated: Use CodeLensWorkspaceClientCapabilities instead. +type WorkspaceClientCapabilitiesCodeLens = CodeLensWorkspaceClientCapabilities + +// WorkspaceClientCapabilitiesDidChangeConfiguration alias of DidChangeConfigurationWorkspaceClientCapabilities. +// +// Deprecated: Use DidChangeConfigurationWorkspaceClientCapabilities instead. +type WorkspaceClientCapabilitiesDidChangeConfiguration = DidChangeConfigurationWorkspaceClientCapabilities + +// WorkspaceClientCapabilitiesDidChangeWatchedFiles alias of DidChangeWatchedFilesWorkspaceClientCapabilities. +// +// Deprecated: Use DidChangeWatchedFilesWorkspaceClientCapabilities instead. +type WorkspaceClientCapabilitiesDidChangeWatchedFiles = DidChangeWatchedFilesWorkspaceClientCapabilities + +// WorkspaceClientCapabilitiesExecuteCommand alias of ExecuteCommandClientCapabilities. +// +// Deprecated: Use ExecuteCommandClientCapabilities instead. +type WorkspaceClientCapabilitiesExecuteCommand = ExecuteCommandClientCapabilities + +// WorkspaceClientCapabilitiesSemanticTokens alias of SemanticTokensWorkspaceClientCapabilities. +// +// Deprecated: Use SemanticTokensWorkspaceClientCapabilities instead. +type WorkspaceClientCapabilitiesSemanticTokens = SemanticTokensWorkspaceClientCapabilities + +// WorkspaceClientCapabilitiesSemanticTokensRequests alias of SemanticTokensWorkspaceClientCapabilitiesRequests. +// +// Deprecated: Use SemanticTokensWorkspaceClientCapabilitiesRequests instead. +type WorkspaceClientCapabilitiesSemanticTokensRequests = SemanticTokensWorkspaceClientCapabilitiesRequests diff --git a/templ/lsp/protocol/diagnostics.go b/templ/lsp/protocol/diagnostics.go new file mode 100644 index 0000000..f88605e --- /dev/null +++ b/templ/lsp/protocol/diagnostics.go @@ -0,0 +1,149 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "strconv" +) + +// Diagnostic represents a diagnostic, such as a compiler error or warning. +// +// Diagnostic objects are only valid in the scope of a resource. +type Diagnostic struct { + // Range is the range at which the message applies. + Range Range `json:"range"` + + // Severity is the diagnostic's severity. Can be omitted. If omitted it is up to the + // client to interpret diagnostics as error, warning, info or hint. + Severity DiagnosticSeverity `json:"severity,omitempty"` + + // Code is the diagnostic's code, which might appear in the user interface. + Code any `json:"code,omitempty"` // int32 | string; + + // CodeDescription an optional property to describe the error code. + // + // @since 3.16.0. + CodeDescription *CodeDescription `json:"codeDescription,omitempty"` + + // Source a human-readable string describing the source of this + // diagnostic, e.g. 'typescript' or 'super lint'. + Source string `json:"source,omitempty"` + + // Message is the diagnostic's message. + Message string `json:"message"` + + // Tags is the additional metadata about the diagnostic. + // + // @since 3.15.0. + Tags []DiagnosticTag `json:"tags,omitempty"` + + // RelatedInformation an array of related diagnostic information, e.g. when symbol-names within + // a scope collide all definitions can be marked via this property. + RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` + + // Data is a data entry field that is preserved between a + // "textDocument/publishDiagnostics" notification and + // "textDocument/codeAction" request. + // + // @since 3.16.0. + Data any `json:"data,omitempty"` +} + +// DiagnosticSeverity indicates the severity of a Diagnostic message. +type DiagnosticSeverity float64 + +const ( + // DiagnosticSeverityError reports an error. + DiagnosticSeverityError DiagnosticSeverity = 1 + + // DiagnosticSeverityWarning reports a warning. + DiagnosticSeverityWarning DiagnosticSeverity = 2 + + // DiagnosticSeverityInformation reports an information. + DiagnosticSeverityInformation DiagnosticSeverity = 3 + + // DiagnosticSeverityHint reports a hint. + DiagnosticSeverityHint DiagnosticSeverity = 4 +) + +// String implements fmt.Stringer. +func (d DiagnosticSeverity) String() string { + switch d { + case DiagnosticSeverityError: + return "Error" + case DiagnosticSeverityWarning: + return "Warning" + case DiagnosticSeverityInformation: + return "Information" + case DiagnosticSeverityHint: + return "Hint" + default: + return strconv.FormatFloat(float64(d), 'f', -10, 64) + } +} + +// CodeDescription is the structure to capture a description for an error code. +// +// @since 3.16.0. +type CodeDescription struct { + // Href an URI to open with more information about the diagnostic error. + Href URI `json:"href"` +} + +// DiagnosticTag is the diagnostic tags. +// +// @since 3.15.0. +type DiagnosticTag float64 + +// list of DiagnosticTag. +const ( + // DiagnosticTagUnnecessary unused or unnecessary code. + // + // Clients are allowed to render diagnostics with this tag faded out instead of having + // an error squiggle. + DiagnosticTagUnnecessary DiagnosticTag = 1 + + // DiagnosticTagDeprecated deprecated or obsolete code. + // + // Clients are allowed to rendered diagnostics with this tag strike through. + DiagnosticTagDeprecated DiagnosticTag = 2 +) + +// String implements fmt.Stringer. +func (d DiagnosticTag) String() string { + switch d { + case DiagnosticTagUnnecessary: + return "Unnecessary" + case DiagnosticTagDeprecated: + return "Deprecated" + default: + return strconv.FormatFloat(float64(d), 'f', -10, 64) + } +} + +// DiagnosticRelatedInformation represents a related message and source code location for a diagnostic. +// +// This should be used to point to code locations that cause or related to a diagnostics, e.g when duplicating +// a symbol in a scope. +type DiagnosticRelatedInformation struct { + // Location is the location of this related diagnostic information. + Location Location `json:"location"` + + // Message is the message of this related diagnostic information. + Message string `json:"message"` +} + +// PublishDiagnosticsParams represents a params of PublishDiagnostics notification. +type PublishDiagnosticsParams struct { + // URI is the URI for which diagnostic information is reported. + URI DocumentURI `json:"uri"` + + // Version optional the version number of the document the diagnostics are published for. + // + // @since 3.15 + Version uint32 `json:"version,omitempty"` + + // Diagnostics an array of diagnostic information items. + Diagnostics []Diagnostic `json:"diagnostics"` +} diff --git a/templ/lsp/protocol/diagnostics_test.go b/templ/lsp/protocol/diagnostics_test.go new file mode 100644 index 0000000..62fa36e --- /dev/null +++ b/templ/lsp/protocol/diagnostics_test.go @@ -0,0 +1,640 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + + "github.com/a-h/templ/lsp/uri" +) + +func TestDiagnostic(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","tags":[1,2],"relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` + wantNilSeverity = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` + wantNilCode = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}` + wantNilRelatedInformation = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","data":"testData"}` + wantNilAll = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"message":"foo bar"}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}],"data":"invalidData"}` + ) + wantType := Diagnostic{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + CodeDescription: &CodeDescription{ + Href: uri.File("/path/to/test.go"), + }, + Source: "test foo bar", + Message: "foo bar", + Tags: []DiagnosticTag{ + DiagnosticTagUnnecessary, + DiagnosticTagDeprecated, + }, + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "basic_gen.go", + }, + }, + Data: "testData", + } + wantTypeNilSeverity := Diagnostic{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Code: "foo/bar", + CodeDescription: &CodeDescription{ + Href: uri.File("/path/to/test.go"), + }, + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "basic_gen.go", + }, + }, + Data: "testData", + } + wantTypeNilCode := Diagnostic{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + CodeDescription: &CodeDescription{ + Href: uri.File("/path/to/test.go"), + }, + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "basic_gen.go", + }, + }, + Data: "testData", + } + wantTypeNilRelatedInformation := Diagnostic{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + CodeDescription: &CodeDescription{ + Href: uri.File("/path/to/test.go"), + }, + Source: "test foo bar", + Message: "foo bar", + Data: "testData", + } + wantTypeNilAll := Diagnostic{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Message: "foo bar", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field Diagnostic + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilSeverity", + field: wantTypeNilSeverity, + want: wantNilSeverity, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilCode", + field: wantTypeNilCode, + want: wantNilCode, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilRelatedInformation", + field: wantTypeNilRelatedInformation, + want: wantNilRelatedInformation, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want Diagnostic + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilSeverity", + field: wantNilSeverity, + want: wantTypeNilSeverity, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilCode", + field: wantNilCode, + want: wantTypeNilCode, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilRelatedInformation", + field: wantNilRelatedInformation, + want: wantTypeNilRelatedInformation, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Diagnostic + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDiagnosticSeverity_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + d DiagnosticSeverity + want string + }{ + { + name: "Error", + d: DiagnosticSeverityError, + want: "Error", + }, + { + name: "Warning", + d: DiagnosticSeverityWarning, + want: "Warning", + }, + { + name: "Information", + d: DiagnosticSeverityInformation, + want: "Information", + }, + { + name: "Hint", + d: DiagnosticSeverityHint, + want: "Hint", + }, + { + name: "Unknown", + d: DiagnosticSeverity(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.d.String(); got != tt.want { + t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestDiagnosticTag_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + d DiagnosticTag + want string + }{ + { + name: "Unnecessary", + d: DiagnosticTagUnnecessary, + want: "Unnecessary", + }, + { + name: "Deprecated", + d: DiagnosticTagDeprecated, + want: "Deprecated", + }, + { + name: "Unknown", + d: DiagnosticTag(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.d.String(); got != tt.want { + t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestDiagnosticRelatedInformation(t *testing.T) { + t.Parallel() + + const ( + want = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}` + wantInvalid = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}` + ) + wantType := DiagnosticRelatedInformation{ + Location: Location{ + URI: uri.File("/path/to/basic.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "basic_gen.go", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DiagnosticRelatedInformation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DiagnosticRelatedInformation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DiagnosticRelatedInformation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestPublishDiagnosticsParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/diagnostics.go","version":1,"diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"diagnostics.go"}]}]}` + wantInvalid = `{"uri":"file:///path/to/diagnostics_gen.go","version":2,"diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics_gen.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"diagnostics_gen.go"}]}]}` + ) + wantType := PublishDiagnosticsParams{ + URI: DocumentURI("file:///path/to/diagnostics.go"), + Version: 1, + Diagnostics: []Diagnostic{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/diagnostics.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "diagnostics.go", + }, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field PublishDiagnosticsParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want PublishDiagnosticsParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got PublishDiagnosticsParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/doc.go b/templ/lsp/protocol/doc.go new file mode 100644 index 0000000..a53cc37 --- /dev/null +++ b/templ/lsp/protocol/doc.go @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +// Package protocol implements Language Server Protocol specification in Go. +// +// This package contains the structs that map directly to the wire format +// of the Language Server Protocol. +// +// It is a literal transcription, with unmodified comments, and only the changes +// required to make it Go code. +// +// - Names are uppercased to export them. +// +// - All fields have JSON tags added to correct the names. +// +// - Fields marked with a ? are also marked as "omitempty". +// +// - Fields that are "|| null" are made pointers. +// +// - Fields that are string or number are left as string. +// +// - Fields that are type "number" are made float64. +package protocol // import "github.com/a-h/templ/lsp/protocol" diff --git a/templ/lsp/protocol/errors.go b/templ/lsp/protocol/errors.go new file mode 100644 index 0000000..e37025f --- /dev/null +++ b/templ/lsp/protocol/errors.go @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import "github.com/a-h/templ/lsp/jsonrpc2" + +const ( + // LSPReservedErrorRangeStart is the start range of LSP reserved error codes. + // + // It doesn't denote a real error code. + // + // @since 3.16.0. + LSPReservedErrorRangeStart jsonrpc2.Code = -32899 + + // ContentModified is the state change that invalidates the result of a request in execution. + // + // Defined by the protocol. + CodeContentModified jsonrpc2.Code = -32801 + + // RequestCancelled is the cancellation error. + // + // Defined by the protocol. + CodeRequestCancelled jsonrpc2.Code = -32800 + + // LSPReservedErrorRangeEnd is the end range of LSP reserved error codes. + // + // It doesn't denote a real error code. + // + // @since 3.16.0. + LSPReservedErrorRangeEnd jsonrpc2.Code = -32800 +) + +var ( + // ErrContentModified should be used when a request is canceled early. + ErrContentModified = jsonrpc2.NewError(CodeContentModified, "cancelled JSON-RPC") + + // ErrRequestCancelled should be used when a request is canceled early. + ErrRequestCancelled = jsonrpc2.NewError(CodeRequestCancelled, "cancelled JSON-RPC") +) diff --git a/templ/lsp/protocol/general.go b/templ/lsp/protocol/general.go new file mode 100644 index 0000000..9fe9ab4 --- /dev/null +++ b/templ/lsp/protocol/general.go @@ -0,0 +1,461 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// TraceValue represents a InitializeParams Trace mode. +type TraceValue string + +// list of TraceValue. +const ( + // TraceOff disable tracing. + TraceOff TraceValue = "off" + + // TraceMessage normal tracing mode. + TraceMessage TraceValue = "message" + + // TraceVerbose verbose tracing mode. + TraceVerbose TraceValue = "verbose" +) + +// ClientInfo information about the client. +// +// @since 3.15.0. +type ClientInfo struct { + // Name is the name of the client as defined by the client. + Name string `json:"name"` + + // Version is the client's version as defined by the client. + Version string `json:"version,omitempty"` +} + +// InitializeParams params of Initialize request. +type InitializeParams struct { + WorkDoneProgressParams + + // ProcessID is the process Id of the parent process that started + // the server. Is null if the process has not been started by another process. + // If the parent process is not alive then the server should exit (see exit notification) its process. + ProcessID int32 `json:"processId"` + + // ClientInfo is the information about the client. + // + // @since 3.15.0 + ClientInfo *ClientInfo `json:"clientInfo,omitempty"` + + // Locale is the locale the client is currently showing the user interface + // in. This must not necessarily be the locale of the operating + // system. + // + // Uses IETF language tags as the value's syntax + // (See https://en.wikipedia.org/wiki/IETF_language_tag) + // + // @since 3.16.0. + Locale string `json:"locale,omitempty"` + + // RootPath is the rootPath of the workspace. Is null + // if no folder is open. + // + // Deprecated: Use RootURI instead. + RootPath string `json:"rootPath,omitempty"` + + // RootURI is the rootUri of the workspace. Is null if no + // folder is open. If both `rootPath` and "rootUri" are set + // "rootUri" wins. + // + // Deprecated: Use WorkspaceFolders instead. + RootURI DocumentURI `json:"rootUri,omitempty"` + + // InitializationOptions user provided initialization options. + InitializationOptions any `json:"initializationOptions,omitempty"` + + // Capabilities is the capabilities provided by the client (editor or tool) + Capabilities ClientCapabilities `json:"capabilities"` + + // Trace is the initial trace setting. If omitted trace is disabled ('off'). + Trace TraceValue `json:"trace,omitempty"` + + // WorkspaceFolders is the workspace folders configured in the client when the server starts. + // This property is only available if the client supports workspace folders. + // It can be `null` if the client supports workspace folders but none are + // configured. + // + // @since 3.6.0. + WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"` +} + +// InitializeResult result of ClientCapabilities. +type InitializeResult struct { + // Capabilities is the capabilities the language server provides. + Capabilities ServerCapabilities `json:"capabilities"` + + // ServerInfo Information about the server. + // + // @since 3.15.0. + ServerInfo *ServerInfo `json:"serverInfo,omitempty"` +} + +// LogTraceParams params of LogTrace notification. +// +// @since 3.16.0. +type LogTraceParams struct { + // Message is the message to be logged. + Message string `json:"message"` + + // Verbose is the additional information that can be computed if the "trace" configuration + // is set to "verbose". + Verbose TraceValue `json:"verbose,omitempty"` +} + +// SetTraceParams params of SetTrace notification. +// +// @since 3.16.0. +type SetTraceParams struct { + // Value is the new value that should be assigned to the trace setting. + Value TraceValue `json:"value"` +} + +// FileOperationPatternKind is a pattern kind describing if a glob pattern matches a file a folder or +// both. +// +// @since 3.16.0. +type FileOperationPatternKind string + +// list of FileOperationPatternKind. +const ( + // FileOperationPatternKindFile is the pattern matches a file only. + FileOperationPatternKindFile FileOperationPatternKind = "file" + + // FileOperationPatternKindFolder is the pattern matches a folder only. + FileOperationPatternKindFolder FileOperationPatternKind = "folder" +) + +// FileOperationPatternOptions matching options for the file operation pattern. +// +// @since 3.16.0. +type FileOperationPatternOptions struct { + // IgnoreCase is The pattern should be matched ignoring casing. + IgnoreCase bool `json:"ignoreCase,omitempty"` +} + +// FileOperationPattern a pattern to describe in which file operation requests or notifications +// the server is interested in. +// +// @since 3.16.0. +type FileOperationPattern struct { + // The glob pattern to match. Glob patterns can have the following syntax: + // - `*` to match one or more characters in a path segment + // - `?` to match on one character in a path segment + // - `**` to match any number of path segments, including none + // - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript + // and JavaScript files) + // - `[]` to declare a range of characters to match in a path segment + // (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + // - `[!...]` to negate a range of characters to match in a path segment + // (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + // not `example.0`) + Glob string `json:"glob"` + + // Matches whether to match files or folders with this pattern. + // + // Matches both if undefined. + Matches FileOperationPatternKind `json:"matches,omitempty"` + + // Options additional options used during matching. + Options FileOperationPatternOptions `json:"options,omitempty"` +} + +// FileOperationFilter is a filter to describe in which file operation requests or notifications +// the server is interested in. +// +// @since 3.16.0. +type FileOperationFilter struct { + // Scheme is a URI like "file" or "untitled". + Scheme string `json:"scheme,omitempty"` + + // Pattern is the actual file operation pattern. + Pattern FileOperationPattern `json:"pattern"` +} + +// CreateFilesParams is the parameters sent in notifications/requests for user-initiated creation +// of files. +// +// @since 3.16.0. +type CreateFilesParams struct { + // Files an array of all files/folders created in this operation. + Files []FileCreate `json:"files"` +} + +// FileCreate nepresents information on a file/folder create. +// +// @since 3.16.0. +type FileCreate struct { + // URI is a file:// URI for the location of the file/folder being created. + URI string `json:"uri"` +} + +// RenameFilesParams is the parameters sent in notifications/requests for user-initiated renames +// of files. +// +// @since 3.16.0. +type RenameFilesParams struct { + // Files an array of all files/folders renamed in this operation. When a folder + // is renamed, only the folder will be included, and not its children. + Files []FileRename `json:"files"` +} + +// FileRename represents information on a file/folder rename. +// +// @since 3.16.0. +type FileRename struct { + // OldURI is a file:// URI for the original location of the file/folder being renamed. + OldURI string `json:"oldUri"` + + // NewURI is a file:// URI for the new location of the file/folder being renamed. + NewURI string `json:"newUri"` +} + +// DeleteFilesParams is the parameters sent in notifications/requests for user-initiated deletes +// of files. +// +// @since 3.16.0. +type DeleteFilesParams struct { + // Files an array of all files/folders deleted in this operation. + Files []FileDelete `json:"files"` +} + +// FileDelete represents information on a file/folder delete. +// +// @since 3.16.0. +type FileDelete struct { + // URI is a file:// URI for the location of the file/folder being deleted. + URI string `json:"uri"` +} + +// DocumentHighlightParams params of DocumentHighlight request. +// +// @since 3.15.0. +type DocumentHighlightParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// DeclarationParams params of Declaration request. +// +// @since 3.15.0. +type DeclarationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// DefinitionParams params of Definition request. +// +// @since 3.15.0. +type DefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// TypeDefinitionParams params of TypeDefinition request. +// +// @since 3.15.0. +type TypeDefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// ImplementationParams params of Implementation request. +// +// @since 3.15.0. +type ImplementationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// ShowDocumentParams params to show a document. +// +// @since 3.16.0. +type ShowDocumentParams struct { + // URI is the document uri to show. + URI URI `json:"uri"` + + // External indicates to show the resource in an external program. + // To show for example `https://code.visualstudio.com/` + // in the default WEB browser set `external` to `true`. + External bool `json:"external,omitempty"` + + // TakeFocus an optional property to indicate whether the editor + // showing the document should take focus or not. + // Clients might ignore this property if an external + // program is started. + TakeFocus bool `json:"takeFocus,omitempty"` + + // Selection an optional selection range if the document is a text + // document. Clients might ignore the property if an + // external program is started or the file is not a text + // file. + Selection *Range `json:"selection,omitempty"` +} + +// ShowDocumentResult is the result of an show document request. +// +// @since 3.16.0. +type ShowDocumentResult struct { + // Success a boolean indicating if the show was successful. + Success bool `json:"success"` +} + +// ServerInfo Information about the server. +// +// @since 3.15.0. +type ServerInfo struct { + // Name is the name of the server as defined by the server. + Name string `json:"name"` + + // Version is the server's version as defined by the server. + Version string `json:"version,omitempty"` +} + +// InitializeError known error codes for an "InitializeError". +type InitializeError struct { + // Retry indicates whether the client execute the following retry logic: + // (1) show the message provided by the ResponseError to the user + // (2) user selects retry or cancel + // (3) if user selected retry the initialize method is sent again. + Retry bool `json:"retry,omitempty"` +} + +// ReferencesOptions ReferencesProvider options. +// +// @since 3.15.0. +type ReferencesOptions struct { + WorkDoneProgressOptions +} + +// WorkDoneProgressOptions WorkDoneProgress options. +// +// @since 3.15.0. +type WorkDoneProgressOptions struct { + WorkDoneProgress bool `json:"workDoneProgress,omitempty"` +} + +// LinkedEditingRangeParams params for the LinkedEditingRange request. +// +// @since 3.16.0. +type LinkedEditingRangeParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +// LinkedEditingRanges result of LinkedEditingRange request. +// +// @since 3.16.0. +type LinkedEditingRanges struct { + // Ranges a list of ranges that can be renamed together. + // + // The ranges must have identical length and contain identical text content. + // + // The ranges cannot overlap. + Ranges []Range `json:"ranges"` + + // WordPattern an optional word pattern (regular expression) that describes valid contents for + // the given ranges. + // + // If no pattern is provided, the client configuration's word pattern will be used. + WordPattern string `json:"wordPattern,omitempty"` +} + +// MonikerParams params for the Moniker request. +// +// @since 3.16.0. +type MonikerParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// UniquenessLevel is the Moniker uniqueness level to define scope of the moniker. +// +// @since 3.16.0. +type UniquenessLevel string + +// list of UniquenessLevel. +const ( + // UniquenessLevelDocument is the moniker is only unique inside a document. + UniquenessLevelDocument UniquenessLevel = "document" + + // UniquenessLevelProject is the moniker is unique inside a project for which a dump got created. + UniquenessLevelProject UniquenessLevel = "project" + + // UniquenessLevelGroup is the moniker is unique inside the group to which a project belongs. + UniquenessLevelGroup UniquenessLevel = "group" + + // UniquenessLevelScheme is the moniker is unique inside the moniker scheme. + UniquenessLevelScheme UniquenessLevel = "scheme" + + // UniquenessLevelGlobal is the moniker is globally unique. + UniquenessLevelGlobal UniquenessLevel = "global" +) + +// MonikerKind is the moniker kind. +// +// @since 3.16.0. +type MonikerKind string + +// list of MonikerKind. +const ( + // MonikerKindImport is the moniker represent a symbol that is imported into a project. + MonikerKindImport MonikerKind = "import" + + // MonikerKindExport is the moniker represents a symbol that is exported from a project. + MonikerKindExport MonikerKind = "export" + + // MonikerKindLocal is the moniker represents a symbol that is local to a project (e.g. a local + // variable of a function, a class not visible outside the project, ...). + MonikerKindLocal MonikerKind = "local" +) + +// Moniker definition to match LSIF 0.5 moniker definition. +// +// @since 3.16.0. +type Moniker struct { + // Scheme is the scheme of the moniker. For example tsc or .Net. + Scheme string `json:"scheme"` + + // Identifier is the identifier of the moniker. + // + // The value is opaque in LSIF however schema owners are allowed to define the structure if they want. + Identifier string `json:"identifier"` + + // Unique is the scope in which the moniker is unique. + Unique UniquenessLevel `json:"unique"` + + // Kind is the moniker kind if known. + Kind MonikerKind `json:"kind,omitempty"` +} + +// StaticRegistrationOptions staticRegistration options to be returned in the initialize request. +type StaticRegistrationOptions struct { + // ID is the id used to register the request. The id can be used to deregister + // the request again. See also Registration#id. + ID string `json:"id,omitempty"` +} + +// DocumentLinkRegistrationOptions DocumentLinkRegistration options. +type DocumentLinkRegistrationOptions struct { + TextDocumentRegistrationOptions + + // ResolveProvider document links have a resolve provider as well. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// InitializedParams params of Initialized notification. +type InitializedParams struct{} + +// WorkspaceFolders represents a slice of WorkspaceFolder. +type WorkspaceFolders []WorkspaceFolder diff --git a/templ/lsp/protocol/general_test.go b/templ/lsp/protocol/general_test.go new file mode 100644 index 0000000..88dea63 --- /dev/null +++ b/templ/lsp/protocol/general_test.go @@ -0,0 +1,5206 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "path/filepath" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/a-h/templ/lsp/uri" +) + +func TestWorkspaceFolders(t *testing.T) { + t.Parallel() + + const want = `[{"uri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/protocol","name":"protocol"},{"uri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/jsonrpc2","name":"jsonrpc2"}]` + wantType := WorkspaceFolders{ + { + URI: string(uri.File("/Users/zchee/go/src/github.com/a-h/templ/lsp/protocol")), + Name: "protocol", + }, + { + URI: string(uri.File("/Users/zchee/go/src/github.com/a-h/templ/lsp/jsonrpc2")), + Name: "jsonrpc2", + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field WorkspaceFolders + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want WorkspaceFolders + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceFolders + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestClientInfo(t *testing.T) { + t.Parallel() + + const ( + want = `{"name":"testClient","version":"v0.0.0"}` + wantNilAll = `{"name":"testClient"}` + ) + wantType := ClientInfo{ + Name: "testClient", + Version: "v0.0.0", + } + wantTypeNilAll := ClientInfo{ + Name: "testClient", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ClientInfo + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ClientInfo + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ClientInfo + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestInitializeParams(t *testing.T) { + t.Parallel() + + const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","processId":25556,"clientInfo":{"name":"testClient","version":"v0.0.0"},"locale":"en-US","rootPath":"~/go/src/github.com/a-h/templ/lsp/protocol","rootUri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/protocol","initializationOptions":"testdata","capabilities":{},"trace":"on","workspaceFolders":[{"uri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/protocol","name":"protocol"},{"uri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/jsonrpc2","name":"jsonrpc2"}]}` + wantNil = `{"processId":25556,"rootUri":"file:///Users/zchee/go/src/github.com/a-h/templ/lsp/protocol","capabilities":{}}` + ) + wantType := InitializeParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + ProcessID: 25556, + ClientInfo: &ClientInfo{ + Name: "testClient", + Version: "v0.0.0", + }, + Locale: "en-US", + RootPath: "~/go/src/github.com/a-h/templ/lsp/protocol", + RootURI: uri.File("/Users/zchee/go/src/github.com/a-h/templ/lsp/protocol"), + InitializationOptions: "testdata", + Capabilities: ClientCapabilities{}, + Trace: "on", + WorkspaceFolders: []WorkspaceFolder{ + { + Name: filepath.Base("/Users/zchee/go/src/github.com/a-h/templ/lsp/protocol"), + URI: string(uri.File("/Users/zchee/go/src/github.com/a-h/templ/lsp/protocol")), + }, + { + Name: filepath.Base("/Users/zchee/go/src/github.com/a-h/templ/lsp/jsonrpc2"), + URI: string(uri.File("/Users/zchee/go/src/github.com/a-h/templ/lsp/jsonrpc2")), + }, + }, + } + wantTypeNilAll := InitializeParams{ + ProcessID: 25556, + RootURI: uri.File("//Users/zchee/go/src/github.com/a-h/templ/lsp/protocol"), + Capabilities: ClientCapabilities{}, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field InitializeParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want InitializeParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got InitializeParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if token := got.WorkDoneToken; token != nil { + if diff := cmp.Diff(fmt.Sprint(token), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestLogTraceParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"message":"testMessage","verbose":"verbose"}` + wantNil = `{"message":"testMessage"}` + ) + wantType := LogTraceParams{ + Message: "testMessage", + Verbose: TraceVerbose, + } + wantTypeNil := LogTraceParams{ + Message: "testMessage", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field LogTraceParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want LogTraceParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got LogTraceParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSetTraceParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"value":"verbose"}` + wantInvalid = `{"value":"invalid"}` + ) + wantType := SetTraceParams{ + Value: TraceVerbose, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field SetTraceParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want SetTraceParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SetTraceParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCreateFilesParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"files":[{"uri":"file:///path/to/basic.go"}]}` + wantInvalid = `{"files":[{"uri":"file:///path/to/invalid.go"}]}` + ) + wantType := CreateFilesParams{ + Files: []FileCreate{ + { + URI: "file:///path/to/basic.go", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CreateFilesParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CreateFilesParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CreateFilesParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameFilesParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"files":[{"oldUri":"file:///path/to/old.go","newUri":"file:///path/to/new.go"}]}` + wantInvalid = `{"files":[{"oldUri":"file:///path/to/invalidOld.go","newUri":"file:///path/to/invalidNew.go"}]}` + ) + wantType := RenameFilesParams{ + Files: []FileRename{ + { + OldURI: "file:///path/to/old.go", + NewURI: "file:///path/to/new.go", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field RenameFilesParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want RenameFilesParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameFilesParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeleteFilesParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"files":[{"uri":"file:///path/to/basic.go"}]}` + wantInvalid = `{"files":[{"uri":"file:///path/to/invalid.go"}]}` + ) + wantType := DeleteFilesParams{ + Files: []FileDelete{ + { + URI: "file:///path/to/basic.go", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeleteFilesParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeleteFilesParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeleteFilesParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestReferencesParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","context":{"includeDeclaration":true}}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"context":{"includeDeclaration":true}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","context":{"includeDeclaration":false}}` + ) + wantType := ReferenceParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + Context: ReferenceContext{ + IncludeDeclaration: true, + }, + } + wantTypeNilAll := ReferenceParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + Context: ReferenceContext{ + IncludeDeclaration: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ReferenceParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ReferenceParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ReferenceParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDocumentHighlightOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := DocumentHighlightOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentHighlightOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentHighlightOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentHighlightOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentHighlightOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentHighlightOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentHighlightParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `"}` + ) + wantType := DocumentHighlightParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + wantTypeNilAll := DocumentHighlightParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentHighlightParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentHighlightParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentHighlightParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDocumentSymbolOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true,"label":"testLabel"}` + wantInvalid = `{"workDoneProgress":false}` + wantNil = `{}` + ) + wantType := DocumentSymbolOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + Label: "testLabel", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentSymbolOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentSymbolOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentSymbolOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentSymbolOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentSymbolOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkspaceSymbolOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantInvalid = `{"workDoneProgress":false}` + wantNil = `{}` + ) + wantType := WorkspaceSymbolOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field WorkspaceSymbolOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: WorkspaceSymbolOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want WorkspaceSymbolOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: WorkspaceSymbolOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceSymbolOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentFormattingOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantInvalid = `{"workDoneProgress":false}` + wantNil = `{}` + ) + wantType := DocumentFormattingOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentFormattingOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentFormattingOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentFormattingOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentFormattingOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentFormattingOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentRangeFormattingOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := DocumentRangeFormattingOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentRangeFormattingOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentRangeFormattingOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentRangeFormattingOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentRangeFormattingOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentRangeFormattingOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeclarationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := DeclarationOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeclarationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DeclarationOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeclarationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DeclarationOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeclarationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeclarationRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true,"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"id":"1"}` + wantNil = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}]}` + wantInvalid = `{"workDoneProgress":false,"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"id":"0"}` + ) + wantType := DeclarationRegistrationOptions{ + DeclarationOptions: DeclarationOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "1", + }, + } + wantTypeNil := DeclarationRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeclarationRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeclarationRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeclarationRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDeclarationParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `"}` + ) + wantType := DeclarationParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + wantTypeNilAll := DeclarationParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DeclarationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DeclarationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DeclarationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDefinitionOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := DefinitionOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DefinitionOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DefinitionOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DefinitionOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DefinitionOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DefinitionOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDefinitionParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `"}` + ) + wantType := DefinitionParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + wantTypeNilAll := DefinitionParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DefinitionParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DefinitionParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DefinitionParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestTypeDefinitionOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := TypeDefinitionOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TypeDefinitionOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: TypeDefinitionOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TypeDefinitionOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: TypeDefinitionOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TypeDefinitionOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTypeDefinitionRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"workDoneProgress":true,"id":"1"}` + wantNil = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"workDoneProgress":false,"id":"0"}` + ) + wantType := TypeDefinitionRegistrationOptions{ + TypeDefinitionOptions: TypeDefinitionOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "1", + }, + } + wantTypeNil := TypeDefinitionRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TypeDefinitionRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TypeDefinitionRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TypeDefinitionRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTypeDefinitionParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `"}` + ) + wantType := TypeDefinitionParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + wantTypeNilAll := TypeDefinitionParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TypeDefinitionParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TypeDefinitionParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TypeDefinitionParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestImplementationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNilAll = `{}` + ) + wantType := ImplementationOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + wantTypeNilAll := ImplementationOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ImplementationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ImplementationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ImplementationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestImplementationRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"workDoneProgress":true,"id":"1"}` + wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"workDoneProgress":false,"id":"0"}` + ) + wantType := ImplementationRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + ImplementationOptions: ImplementationOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "1", + }, + } + wantTypeNilAll := ImplementationRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ImplementationRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ImplementationRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ImplementationRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestImplementationParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `"}` + ) + wantType := ImplementationParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + wantTypeNilAll := ImplementationParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ImplementationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ImplementationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ImplementationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDocumentColorOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := DocumentColorOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentColorOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: DocumentColorOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentColorOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: DocumentColorOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentColorOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentColorRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"id":"1","workDoneProgress":true}` + wantNil = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"id":"0","workDoneProgress":false}` + ) + wantType := DocumentColorRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "1", + }, + DocumentColorOptions: DocumentColorOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + } + wantTypeNil := DocumentColorRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentColorRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentColorRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentColorRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestPrepareSupportDefaultBehavior_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k PrepareSupportDefaultBehavior + want string + }{ + { + name: "Identifier", + k: PrepareSupportDefaultBehaviorIdentifier, + want: "Identifier", + }, + { + name: "UnknownKind", + k: PrepareSupportDefaultBehavior(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("PrepareSupportDefaultBehavior.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestFoldingRangeOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + wantInvalid = `{"workDoneProgress":false}` + ) + wantType := FoldingRangeOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field FoldingRangeOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: FoldingRangeOptions{}, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want FoldingRangeOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: FoldingRangeOptions{}, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FoldingRangeOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestFoldingRangeRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"workDoneProgress":true,"id":"1"}` + wantNil = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"workDoneProgress":false,"id":"0"}` + ) + wantType := FoldingRangeRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + FoldingRangeOptions: FoldingRangeOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: "1", + }, + } + wantTypeNil := FoldingRangeRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field FoldingRangeRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want FoldingRangeRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FoldingRangeRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestInitializeResult(t *testing.T) { + t.Parallel() + + const ( + want = `{"capabilities":{"textDocumentSync":1,"completionProvider":{"resolveProvider":true,"triggerCharacters":["Tab"]},"hoverProvider":true,"signatureHelpProvider":{"triggerCharacters":["C-K"],"retriggerCharacters":["."]},"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":true,"referencesProvider":true,"documentHighlightProvider":true,"documentSymbolProvider":true,"codeActionProvider":true,"codeLensProvider":{"resolveProvider":true},"documentLinkProvider":{"resolveProvider":true},"colorProvider":true,"workspaceSymbolProvider":true,"documentFormattingProvider":true,"documentRangeFormattingProvider":true,"documentOnTypeFormattingProvider":{"firstTriggerCharacter":".","moreTriggerCharacter":["f"]},"renameProvider":true,"foldingRangeProvider":true,"selectionRangeProvider":true,"executeCommandProvider":{"commands":["test","command"]},"callHierarchyProvider":true,"linkedEditingRangeProvider":true,"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":"testNotifications"},"fileOperations":{"didCreate":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"file","options":{"ignoreCase":true}}}]},"willCreate":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"folder","options":{"ignoreCase":true}}}]},"didRename":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"file","options":{"ignoreCase":true}}}]},"willRename":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"folder","options":{"ignoreCase":true}}}]},"didDelete":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"file","options":{"ignoreCase":true}}}]},"willDelete":{"filters":[{"scheme":"file","pattern":{"glob":"*","matches":"folder","options":{"ignoreCase":true}}}]}}},"monikerProvider":true,"experimental":"Awesome Experimentals"},"serverInfo":{"name":"testServer","version":"v0.0.0"}}` + wantNil = `{"capabilities":{}}` + ) + wantType := InitializeResult{ + Capabilities: ServerCapabilities{ + TextDocumentSync: float64(1), + CompletionProvider: &CompletionOptions{ + ResolveProvider: true, + TriggerCharacters: []string{"Tab"}, + }, + HoverProvider: true, + SignatureHelpProvider: &SignatureHelpOptions{ + TriggerCharacters: []string{"C-K"}, + RetriggerCharacters: []string{"."}, + }, + DeclarationProvider: true, + DefinitionProvider: true, + TypeDefinitionProvider: true, + ImplementationProvider: true, + ReferencesProvider: true, + DocumentHighlightProvider: true, + DocumentSymbolProvider: true, + WorkspaceSymbolProvider: true, + CodeActionProvider: true, + CodeLensProvider: &CodeLensOptions{ + ResolveProvider: true, + }, + DocumentFormattingProvider: true, + DocumentRangeFormattingProvider: true, + DocumentOnTypeFormattingProvider: &DocumentOnTypeFormattingOptions{ + FirstTriggerCharacter: ".", + MoreTriggerCharacter: []string{"f"}, + }, + RenameProvider: true, + DocumentLinkProvider: &DocumentLinkOptions{ + ResolveProvider: true, + }, + ColorProvider: true, + FoldingRangeProvider: true, + SelectionRangeProvider: true, + ExecuteCommandProvider: &ExecuteCommandOptions{ + Commands: []string{"test", "command"}, + }, + Workspace: &ServerCapabilitiesWorkspace{ + WorkspaceFolders: &ServerCapabilitiesWorkspaceFolders{ + Supported: true, + ChangeNotifications: "testNotifications", + }, + FileOperations: &ServerCapabilitiesWorkspaceFileOperations{ + DidCreate: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFile, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + WillCreate: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFolder, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + DidRename: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFile, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + WillRename: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFolder, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + DidDelete: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFile, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + WillDelete: &FileOperationRegistrationOptions{ + Filters: []FileOperationFilter{ + { + Scheme: "file", + Pattern: FileOperationPattern{ + Glob: "*", + Matches: FileOperationPatternKindFolder, + Options: FileOperationPatternOptions{ + IgnoreCase: true, + }, + }, + }, + }, + }, + }, + }, + LinkedEditingRangeProvider: true, + CallHierarchyProvider: true, + SemanticTokensProvider: nil, + MonikerProvider: true, + Experimental: "Awesome Experimentals", + }, + ServerInfo: &ServerInfo{ + Name: "testServer", + Version: "v0.0.0", + }, + } + wantTypeNil := InitializeResult{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field InitializeResult + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Logf("got: %s", string(got)) + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want InitializeResult + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got InitializeResult + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + // cmpOpts := cmpopts.IgnoreFields(ServerCapabilities{}, "SelectionRangeProvider") // ignore SelectionRangeProvider field but assert below + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + // if srp := got.Capabilities.SelectionRangeProvider; srp != nil { + // switch srp := srp.(type) { + // case bool: // EnableSelectionRange + // if diff := cmp.Diff(EnableSelectionRange(srp), enableSelectionRange); (diff != "") != tt.wantErr { + // t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + // } + // default: + // t.Fatalf("srp type is %[1]T, not bool: %#[1]v\n", srp) + // } + // } + }) + } + }) +} + +func TestInitializeError(t *testing.T) { + t.Parallel() + + const want = `{"retry":true}` + wantType := InitializeError{ + Retry: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field InitializeError + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want InitializeError + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got InitializeError + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestShowDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"file:///path/to/basic.go","external":true,"takeFocus":true,"selection":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}}}` + wantNil = `{"uri":"file:///path/to/basic.go"}` + ) + wantType := ShowDocumentParams{ + URI: uri.File("/path/to/basic.go"), + External: true, + TakeFocus: true, + Selection: &Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + } + wantTypeNilAll := ShowDocumentParams{ + URI: uri.File("/path/to/basic.go"), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ShowDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ShowDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ShowDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestShowDocumentResult(t *testing.T) { + t.Parallel() + + const want = `{"success":true}` + wantType := ShowDocumentResult{ + Success: true, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ShowDocumentResult + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ShowDocumentResult + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ShowDocumentResult + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentSyncKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k TextDocumentSyncKind + want string + }{ + { + name: "NoneKind", + k: TextDocumentSyncKindNone, + want: "None", + }, + { + name: "FullKind", + k: TextDocumentSyncKindFull, + want: "Full", + }, + { + name: "IncrementalKind", + k: TextDocumentSyncKindIncremental, + want: "Incremental", + }, + { + name: "UnknownKind", + k: TextDocumentSyncKind(99), + want: "99", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("TextDocumentSyncKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestReferencesOptions(t *testing.T) { + t.Parallel() + + const want = `{"workDoneProgress":true}` + wantType := ReferencesOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ReferencesOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ReferencesOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ReferencesOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeActionOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"codeActionKinds":["quickfix","refactor"],"resolveProvider":true}` + wantNil = `{}` + ) + wantType := CodeActionOptions{ + CodeActionKinds: []CodeActionKind{ + QuickFix, + Refactor, + }, + ResolveProvider: true, + } + wantTypeNil := CodeActionOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field CodeActionOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want CodeActionOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeActionOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"prepareProvider":true}` + wantNil = `{}` + ) + wantType := RenameOptions{ + PrepareProvider: true, + } + wantTypeNil := RenameOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field RenameOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want RenameOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSaveOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"includeText":true}` + wantNil = `{}` + ) + wantType := SaveOptions{ + IncludeText: true, + } + wantTypeNil := SaveOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field SaveOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want SaveOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SaveOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentSyncOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"openClose":true,"change":1,"willSave":true,"willSaveWaitUntil":true,"save":{"includeText":true}}` + wantNil = `{}` + ) + wantType := TextDocumentSyncOptions{ + OpenClose: true, + Change: TextDocumentSyncKindFull, + WillSave: true, + WillSaveWaitUntil: true, + Save: &SaveOptions{ + IncludeText: true, + }, + } + wantTypeNil := TextDocumentSyncOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field TextDocumentSyncOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want TextDocumentSyncOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentSyncOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestHoverOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"workDoneProgress":true}` + wantNil = `{}` + ) + wantType := HoverOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: true, + }, + } + wantTypeNil := HoverOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field HoverOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want HoverOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got HoverOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestStaticRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"id":"testID"}` + wantNil = `{}` + ) + wantType := StaticRegistrationOptions{ + ID: "testID", + } + wantTypeNil := StaticRegistrationOptions{} + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field StaticRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want StaticRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got StaticRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentLinkRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*"}],"resolveProvider":true}` + wantNil = `{"documentSelector":[]}` + ) + wantType := DocumentLinkRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: `*`, + }, + }, + }, + ResolveProvider: true, + } + wantTypeNilAll := DocumentLinkRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{}, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field DocumentLinkRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want DocumentLinkRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentLinkRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestInitializedParams(t *testing.T) { + t.Parallel() + + const want = `{}` + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field InitializedParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: InitializedParams{}, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want InitializedParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: InitializedParams{}, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got InitializedParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/handler.go b/templ/lsp/protocol/handler.go new file mode 100644 index 0000000..0cd437a --- /dev/null +++ b/templ/lsp/protocol/handler.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "context" + "fmt" + + "encoding/json" + + "github.com/a-h/templ/lsp/jsonrpc2" + "github.com/a-h/templ/lsp/xcontext" +) + +// CancelHandler handler of cancelling. +func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler { + handler, canceller := jsonrpc2.CancelHandler(handler) + + h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { + if req.Method() != MethodCancelRequest { + // TODO(iancottrell): See if we can generate a reply for the request to be cancelled + // at the point of cancellation rather than waiting for gopls to naturally reply. + // To do that, we need to keep track of whether a reply has been sent already and + // be careful about racing between the two paths. + // TODO(iancottrell): Add a test that watches the stream and verifies the response + // for the cancelled request flows. + reply := func(ctx context.Context, resp any, err error) error { + // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest + if ctx.Err() != nil && err == nil { + err = ErrRequestCancelled + } + ctx = xcontext.Detach(ctx) + + return reply(ctx, resp, err) + } + + return handler(ctx, reply, req) + } + + var params CancelParams + if err := json.Unmarshal(req.Params(), ¶ms); err != nil { + return replyParseError(ctx, reply, err) + } + + switch id := params.ID.(type) { + case int32: + canceller(jsonrpc2.NewNumberID(id)) + case string: + canceller(jsonrpc2.NewStringID(id)) + default: + return replyParseError(ctx, reply, fmt.Errorf("request ID %v malformed", id)) + } + + return reply(ctx, nil, nil) + } + + return h +} + +// Handlers default jsonrpc2.Handler. +func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler { + return CancelHandler( + jsonrpc2.AsyncHandler( + jsonrpc2.ReplyHandler(handler), + ), + ) +} + +// Call calls method to params and result. +func Call(ctx context.Context, conn jsonrpc2.Conn, method string, params, result any) error { + id, err := conn.Call(ctx, method, params, result) + if ctx.Err() != nil { + notifyCancel(ctx, conn, id) + } + + return err +} + +func notifyCancel(ctx context.Context, conn jsonrpc2.Conn, id jsonrpc2.ID) { + ctx = xcontext.Detach(ctx) + // Note that only *jsonrpc2.ID implements json.Marshaler. + _ = conn.Notify(ctx, MethodCancelRequest, &CancelParams{ID: &id}) +} + +func replyParseError(ctx context.Context, reply jsonrpc2.Replier, err error) error { + return reply(ctx, nil, fmt.Errorf("%s: %w", jsonrpc2.ErrParse, err)) +} diff --git a/templ/lsp/protocol/language.go b/templ/lsp/protocol/language.go new file mode 100644 index 0000000..37e60c8 --- /dev/null +++ b/templ/lsp/protocol/language.go @@ -0,0 +1,1401 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "strconv" + + "encoding/json" +) + +// CompletionParams params of Completion request. +type CompletionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams + + // Context is the completion context. This is only available if the client specifies + // to send this using `ClientCapabilities.textDocument.completion.contextSupport === true` + Context *CompletionContext `json:"context,omitempty"` +} + +// CompletionTriggerKind how a completion was triggered. +type CompletionTriggerKind float64 + +const ( + // CompletionTriggerKindInvoked completion was triggered by typing an identifier (24x7 code + // complete), manual invocation (e.g Ctrl+Space) or via API. + CompletionTriggerKindInvoked CompletionTriggerKind = 1 + + // CompletionTriggerKindTriggerCharacter completion was triggered by a trigger character specified by + // the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + CompletionTriggerKindTriggerCharacter CompletionTriggerKind = 2 + + // CompletionTriggerKindTriggerForIncompleteCompletions completion was re-triggered as the current completion list is incomplete. + CompletionTriggerKindTriggerForIncompleteCompletions CompletionTriggerKind = 3 +) + +// String implements fmt.Stringer. +func (k CompletionTriggerKind) String() string { + switch k { + case CompletionTriggerKindInvoked: + return "Invoked" + case CompletionTriggerKindTriggerCharacter: + return "TriggerCharacter" + case CompletionTriggerKindTriggerForIncompleteCompletions: + return "TriggerForIncompleteCompletions" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// CompletionContext contains additional information about the context in which a completion request is triggered. +type CompletionContext struct { + // TriggerCharacter is the trigger character (a single character) that has trigger code complete. + // Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + TriggerCharacter string `json:"triggerCharacter,omitempty"` + + // TriggerKind how the completion was triggered. + TriggerKind CompletionTriggerKind `json:"triggerKind"` +} + +// CompletionList represents a collection of [completion items](#CompletionItem) to be presented +// in the editor. +type CompletionList struct { + // IsIncomplete this list it not complete. Further typing should result in recomputing + // this list. + IsIncomplete bool `json:"isIncomplete"` + + // Items is the completion items. + Items []CompletionItem `json:"items"` +} + +// InsertTextFormat defines whether the insert text in a completion item should be interpreted as +// plain text or a snippet. +type InsertTextFormat float64 + +const ( + // InsertTextFormatPlainText is the primary text to be inserted is treated as a plain string. + InsertTextFormatPlainText InsertTextFormat = 1 + + // InsertTextFormatSnippet is the primary text to be inserted is treated as a snippet. + // + // A snippet can define tab stops and placeholders with `$1`, `$2` + // and `${3:foo}`. `$0` defines the final tab stop, it defaults to + // the end of the snippet. Placeholders with equal identifiers are linked, + // that is typing in one will update others too. + InsertTextFormatSnippet InsertTextFormat = 2 +) + +// String implements fmt.Stringer. +func (tf InsertTextFormat) String() string { + switch tf { + case InsertTextFormatPlainText: + return "PlainText" + case InsertTextFormatSnippet: + return "Snippet" + default: + return strconv.FormatFloat(float64(tf), 'f', -10, 64) + } +} + +// InsertReplaceEdit is a special text edit to provide an insert and a replace operation. +// +// @since 3.16.0. +type InsertReplaceEdit struct { + // NewText is the string to be inserted. + NewText string `json:"newText"` + + // Insert is the range if the insert is requested. + Insert Range `json:"insert"` + + // Replace is the range if the replace is requested. + Replace Range `json:"replace"` +} + +// InsertTextMode how whitespace and indentation is handled during completion +// item insertion. +// +// @since 3.16.0. +type InsertTextMode float64 + +const ( + // AsIs is the insertion or replace strings is taken as it is. If the + // value is multi line the lines below the cursor will be + // inserted using the indentation defined in the string value. + // The client will not apply any kind of adjustments to the + // string. + InsertTextModeAsIs InsertTextMode = 1 + + // AdjustIndentation is the editor adjusts leading whitespace of new lines so that + // they match the indentation up to the cursor of the line for + // which the item is accepted. + // + // Consider a line like this: <2tabs><3tabs>foo. Accepting a + // multi line completion item is indented using 2 tabs and all + // following lines inserted will be indented using 2 tabs as well. + InsertTextModeAdjustIndentation InsertTextMode = 2 +) + +// String returns a string representation of the InsertTextMode. +func (k InsertTextMode) String() string { + switch k { + case InsertTextModeAsIs: + return "AsIs" + case InsertTextModeAdjustIndentation: + return "AdjustIndentation" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// CompletionItem item of CompletionList. +type CompletionItem struct { + // AdditionalTextEdits an optional array of additional text edits that are applied when + // selecting this completion. Edits must not overlap (including the same insert position) + // with the main edit nor with themselves. + // + // Additional text edits should be used to change text unrelated to the current cursor position + // (for example adding an import statement at the top of the file if the completion item will + // insert an unqualified type). + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` + + // Command an optional command that is executed *after* inserting this completion. *Note* that + // additional modifications to the current document should be described with the + // additionalTextEdits-property. + Command *Command `json:"command,omitempty"` + + // CommitCharacters an optional set of characters that when pressed while this completion is active will accept it first and + // then type that character. *Note* that all commit characters should have `length=1` and that superfluous + // characters will be ignored. + CommitCharacters []string `json:"commitCharacters,omitempty"` + + // Tags is the tag for this completion item. + // + // @since 3.15.0. + Tags []CompletionItemTag `json:"tags,omitempty"` + + // Data an data entry field that is preserved on a completion item between + // a completion and a completion resolve request. + Data any `json:"data,omitempty"` + + // Deprecated indicates if this item is deprecated. + Deprecated bool `json:"deprecated,omitempty"` + + // Detail a human-readable string with additional information + // about this item, like type or symbol information. + Detail string `json:"detail,omitempty"` + + // Documentation a human-readable string that represents a doc-comment. + Documentation any `json:"documentation,omitempty"` + + // FilterText a string that should be used when filtering a set of + // completion items. When `falsy` the label is used. + FilterText string `json:"filterText,omitempty"` + + // InsertText a string that should be inserted into a document when selecting + // this completion. When `falsy` the label is used. + // + // The `insertText` is subject to interpretation by the client side. + // Some tools might not take the string literally. For example + // VS Code when code complete is requested in this example `con` + // and a completion item with an `insertText` of `console` is provided it + // will only insert `sole`. Therefore it is recommended to use `textEdit` instead + // since it avoids additional client side interpretation. + InsertText string `json:"insertText,omitempty"` + + // InsertTextFormat is the format of the insert text. The format applies to both the `insertText` property + // and the `newText` property of a provided `textEdit`. + InsertTextFormat InsertTextFormat `json:"insertTextFormat,omitempty"` + + // InsertTextMode how whitespace and indentation is handled during completion + // item insertion. If not provided the client's default value depends on + // the `textDocument.completion.insertTextMode` client capability. + // + // @since 3.16.0. + InsertTextMode InsertTextMode `json:"insertTextMode,omitempty"` + + // Kind is the kind of this completion item. Based of the kind + // an icon is chosen by the editor. + Kind CompletionItemKind `json:"kind,omitempty"` + + // Label is the label of this completion item. By default + // also the text that is inserted when selecting + // this completion. + Label string `json:"label"` + + // Preselect select this item when showing. + // + // *Note* that only one completion item can be selected and that the + // tool / client decides which item that is. The rule is that the *first* + // item of those that match best is selected. + Preselect bool `json:"preselect,omitempty"` + + // SortText a string that should be used when comparing this item + // with other items. When `falsy` the label is used. + SortText string `json:"sortText,omitempty"` + + // TextEdit an edit which is applied to a document when selecting this completion. When an edit is provided the value of + // `insertText` is ignored. + // + // NOTE: The range of the edit must be a single line range and it must contain the position at which completion + // has been requested. + // + // Most editors support two different operations when accepting a completion + // item. One is to insert a completion text and the other is to replace an + // existing text with a completion text. Since this can usually not be + // predetermined by a server it can report both ranges. Clients need to + // signal support for `InsertReplaceEdits` via the + // "textDocument.completion.insertReplaceSupport" client capability + // property. + // + // NOTE 1: The text edit's range as well as both ranges from an insert + // replace edit must be a [single line] and they must contain the position + // at which completion has been requested. + // + // NOTE 2: If an "InsertReplaceEdit" is returned the edit's insert range + // must be a prefix of the edit's replace range, that means it must be + // contained and starting at the same position. + // + // @since 3.16.0 additional type "InsertReplaceEdit". + TextEdit *TextEditOrInsertReplaceEdit `json:"textEdit,omitempty"` // *TextEdit | *InsertReplaceEdit +} + +type TextEditOrInsertReplaceEdit struct { + TextEdit *TextEdit + InsertReplaceEdit *InsertReplaceEdit +} + +func (t *TextEditOrInsertReplaceEdit) MarshalJSON() ([]byte, error) { + if t.TextEdit != nil { + return json.Marshal(t.TextEdit) + } + return json.Marshal(t.InsertReplaceEdit) +} + +type textEditAndInsertReplaceEdit struct { + // NewText is in both types. + NewText string `json:"newText"` + + // Range is only present in TextEdit. + Range *Range `json:"range"` + + // Insert is only present in InsertReplaceEdit. + Insert Range `json:"insert"` + // Replace is only present in InsertReplaceEdit. + Replace Range `json:"replace"` +} + +func (t *TextEditOrInsertReplaceEdit) UnmarshalJSON(data []byte) error { + var teaire textEditAndInsertReplaceEdit + if err := json.Unmarshal(data, &teaire); err != nil { + return err + } + if teaire.Range != nil { + t.TextEdit = &TextEdit{ + NewText: teaire.NewText, + Range: *teaire.Range, + } + return nil + } + t.InsertReplaceEdit = &InsertReplaceEdit{ + NewText: teaire.NewText, + Insert: teaire.Insert, + Replace: teaire.Replace, + } + return nil +} + +// CompletionItemKind is the completion item kind values the client supports. When this +// property exists the client also guarantees that it will +// handle values outside its set gracefully and falls back +// to a default value when unknown. +// +// If this property is not present the client only supports +// the completion items kinds from `Text` to `Reference` as defined in +// the initial version of the protocol. +type CompletionItemKind float64 + +const ( + // CompletionItemKindText text completion kind. + CompletionItemKindText CompletionItemKind = 1 + // CompletionItemKindMethod method completion kind. + CompletionItemKindMethod CompletionItemKind = 2 + // CompletionItemKindFunction function completion kind. + CompletionItemKindFunction CompletionItemKind = 3 + // CompletionItemKindConstructor constructor completion kind. + CompletionItemKindConstructor CompletionItemKind = 4 + // CompletionItemKindField field completion kind. + CompletionItemKindField CompletionItemKind = 5 + // CompletionItemKindVariable variable completion kind. + CompletionItemKindVariable CompletionItemKind = 6 + // CompletionItemKindClass class completion kind. + CompletionItemKindClass CompletionItemKind = 7 + // CompletionItemKindInterface interface completion kind. + CompletionItemKindInterface CompletionItemKind = 8 + // CompletionItemKindModule module completion kind. + CompletionItemKindModule CompletionItemKind = 9 + // CompletionItemKindProperty property completion kind. + CompletionItemKindProperty CompletionItemKind = 10 + // CompletionItemKindUnit unit completion kind. + CompletionItemKindUnit CompletionItemKind = 11 + // CompletionItemKindValue value completion kind. + CompletionItemKindValue CompletionItemKind = 12 + // CompletionItemKindEnum enum completion kind. + CompletionItemKindEnum CompletionItemKind = 13 + // CompletionItemKindKeyword keyword completion kind. + CompletionItemKindKeyword CompletionItemKind = 14 + // CompletionItemKindSnippet snippet completion kind. + CompletionItemKindSnippet CompletionItemKind = 15 + // CompletionItemKindColor color completion kind. + CompletionItemKindColor CompletionItemKind = 16 + // CompletionItemKindFile file completion kind. + CompletionItemKindFile CompletionItemKind = 17 + // CompletionItemKindReference reference completion kind. + CompletionItemKindReference CompletionItemKind = 18 + // CompletionItemKindFolder folder completion kind. + CompletionItemKindFolder CompletionItemKind = 19 + // CompletionItemKindEnumMember enum member completion kind. + CompletionItemKindEnumMember CompletionItemKind = 20 + // CompletionItemKindConstant constant completion kind. + CompletionItemKindConstant CompletionItemKind = 21 + // CompletionItemKindStruct struct completion kind. + CompletionItemKindStruct CompletionItemKind = 22 + // CompletionItemKindEvent event completion kind. + CompletionItemKindEvent CompletionItemKind = 23 + // CompletionItemKindOperator operator completion kind. + CompletionItemKindOperator CompletionItemKind = 24 + // CompletionItemKindTypeParameter type parameter completion kind. + CompletionItemKindTypeParameter CompletionItemKind = 25 +) + +// String implements fmt.Stringer. +// +//nolint:cyclop +func (k CompletionItemKind) String() string { + switch k { + case CompletionItemKindText: + return "Text" + case CompletionItemKindMethod: + return "Method" + case CompletionItemKindFunction: + return "Function" + case CompletionItemKindConstructor: + return "Constructor" + case CompletionItemKindField: + return "Field" + case CompletionItemKindVariable: + return "Variable" + case CompletionItemKindClass: + return "Class" + case CompletionItemKindInterface: + return "Interface" + case CompletionItemKindModule: + return "Module" + case CompletionItemKindProperty: + return "Property" + case CompletionItemKindUnit: + return "Unit" + case CompletionItemKindValue: + return "Value" + case CompletionItemKindEnum: + return "Enum" + case CompletionItemKindKeyword: + return "Keyword" + case CompletionItemKindSnippet: + return "Snippet" + case CompletionItemKindColor: + return "Color" + case CompletionItemKindFile: + return "File" + case CompletionItemKindReference: + return "Reference" + case CompletionItemKindFolder: + return "Folder" + case CompletionItemKindEnumMember: + return "EnumMember" + case CompletionItemKindConstant: + return "Constant" + case CompletionItemKindStruct: + return "Struct" + case CompletionItemKindEvent: + return "Event" + case CompletionItemKindOperator: + return "Operator" + case CompletionItemKindTypeParameter: + return "TypeParameter" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// CompletionItemTag completion item tags are extra annotations that tweak the rendering of a completion +// item. +// +// @since 3.15.0. +type CompletionItemTag float64 + +// list of CompletionItemTag. +const ( + // CompletionItemTagDeprecated is the render a completion as obsolete, usually using a strike-out. + CompletionItemTagDeprecated CompletionItemTag = 1 +) + +// String returns a string representation of the type. +func (c CompletionItemTag) String() string { + switch c { + case CompletionItemTagDeprecated: + return "Deprecated" + default: + return strconv.FormatFloat(float64(c), 'f', -10, 64) + } +} + +// CompletionRegistrationOptions CompletionRegistration options. +type CompletionRegistrationOptions struct { + TextDocumentRegistrationOptions + + // TriggerCharacters most tools trigger completion request automatically without explicitly requesting + // it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user + // starts to type an identifier. For example if the user types `c` in a JavaScript file + // code complete will automatically pop up present `console` besides others as a + // completion item. Characters that make up identifiers don't need to be listed here. + // + // If code complete should automatically be trigger on characters not being valid inside + // an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + // ResolveProvider is the server provides support to resolve additional + // information for a completion item. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// HoverParams params of Hover request. +// +// @since 3.15.0. +type HoverParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +// Hover is the result of a hover request. +type Hover struct { + // Contents is the hover's content + Contents MarkupContent `json:"contents"` + + // Range an optional range is a range inside a text document + // that is used to visualize a hover, e.g. by changing the background color. + Range *Range `json:"range,omitempty"` +} + +// SignatureHelpParams params of SignatureHelp request. +// +// @since 3.15.0. +type SignatureHelpParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + + // context is the signature help context. + // + // This is only available if the client specifies to send this using the + // client capability `textDocument.signatureHelp.contextSupport === true`. + // + // @since 3.15.0. + Context *SignatureHelpContext `json:"context,omitempty"` +} + +// SignatureHelpTriggerKind is the how a signature help was triggered. +// +// @since 3.15.0. +type SignatureHelpTriggerKind float64 + +// list of SignatureHelpTriggerKind. +const ( + // SignatureHelpTriggerKindInvoked is the signature help was invoked manually by the user or by a command. + SignatureHelpTriggerKindInvoked SignatureHelpTriggerKind = 1 + + // SignatureHelpTriggerKindTriggerCharacter is the signature help was triggered by a trigger character. + SignatureHelpTriggerKindTriggerCharacter SignatureHelpTriggerKind = 2 + + // SignatureHelpTriggerKindContentChange is the signature help was triggered by the cursor moving or + // by the document content changing. + SignatureHelpTriggerKindContentChange SignatureHelpTriggerKind = 3 +) + +// String returns a string representation of the type. +func (s SignatureHelpTriggerKind) String() string { + switch s { + case SignatureHelpTriggerKindInvoked: + return "Invoked" + case SignatureHelpTriggerKindTriggerCharacter: + return "TriggerCharacter" + case SignatureHelpTriggerKindContentChange: + return "ContentChange" + default: + return strconv.FormatFloat(float64(s), 'f', -10, 64) + } +} + +// SignatureHelpContext is the additional information about the context in which a +// signature help request was triggered. +// +// @since 3.15.0. +type SignatureHelpContext struct { + // TriggerKind is the action that caused signature help to be triggered. + TriggerKind SignatureHelpTriggerKind `json:"triggerKind"` + + // Character that caused signature help to be triggered. + // + // This is undefined when + // TriggerKind != SignatureHelpTriggerKindTriggerCharacter + TriggerCharacter string `json:"triggerCharacter,omitempty"` + + // IsRetrigger is the `true` if signature help was already showing when it was triggered. + // + // Retriggers occur when the signature help is already active and can be + // caused by actions such as typing a trigger character, a cursor move, + // or document content changes. + IsRetrigger bool `json:"isRetrigger"` + + // ActiveSignatureHelp is the currently active SignatureHelp. + // + // The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field + // updated based on the user navigating through available signatures. + ActiveSignatureHelp *SignatureHelp `json:"activeSignatureHelp,omitempty"` +} + +// SignatureHelp signature help represents the signature of something +// callable. There can be multiple signature but only one +// active and only one active parameter. +type SignatureHelp struct { + // Signatures one or more signatures. + Signatures []SignatureInformation `json:"signatures"` + + // ActiveParameter is the active parameter of the active signature. If omitted or the value + // lies outside the range of `signatures[activeSignature].parameters` + // defaults to 0 if the active signature has parameters. If + // the active signature has no parameters it is ignored. + // In future version of the protocol this property might become + // mandatory to better express the active parameter if the + // active signature does have any. + ActiveParameter uint32 `json:"activeParameter,omitempty"` + + // ActiveSignature is the active signature. If omitted or the value lies outside the + // range of `signatures` the value defaults to zero or is ignored if + // `signatures.length === 0`. Whenever possible implementors should + // make an active decision about the active signature and shouldn't + // rely on a default value. + // In future version of the protocol this property might become + // mandatory to better express this. + ActiveSignature uint32 `json:"activeSignature,omitempty"` +} + +// SignatureInformation is the client supports the following `SignatureInformation` +// specific properties. +type SignatureInformation struct { + // Label is the label of this signature. Will be shown in + // the UI. + // + // @since 3.16.0. + Label string `json:"label"` + + // Documentation is the human-readable doc-comment of this signature. Will be shown + // in the UI but can be omitted. + // + // @since 3.16.0. + Documentation any `json:"documentation,omitempty"` // string | *MarkupContent + + // Parameters is the parameters of this signature. + // + // @since 3.16.0. + Parameters []ParameterInformation `json:"parameters,omitempty"` + + // ActiveParameterSupport is the client supports the `activeParameter` property on + // `SignatureInformation` literal. + // + // @since 3.16.0. + ActiveParameter uint32 `json:"activeParameter,omitempty"` +} + +// ParameterInformation represents a parameter of a callable-signature. A parameter can +// have a label and a doc-comment. +type ParameterInformation struct { + // Label is the label of this parameter information. + // + // Either a string or an inclusive start and exclusive end offsets within its containing + // signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 + // string representation as "Position" and "Range" does. + // + // *Note*: a label of type string should be a substring of its containing signature label. + // Its intended use case is to highlight the parameter label part in the "SignatureInformation.label". + Label string `json:"label"` // string | [uint32, uint32] + + // Documentation is the human-readable doc-comment of this parameter. Will be shown + // in the UI but can be omitted. + Documentation any `json:"documentation,omitempty"` // string | MarkupContent +} + +// SignatureHelpRegistrationOptions SignatureHelp Registration options. +type SignatureHelpRegistrationOptions struct { + TextDocumentRegistrationOptions + + // TriggerCharacters is the characters that trigger signature help + // automatically. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` +} + +// ReferenceParams params of References request. +// +// @since 3.15.0. +type ReferenceParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams + + // Context is the ReferenceParams context. + Context ReferenceContext `json:"context"` +} + +// ReferenceContext context of ReferenceParams. +type ReferenceContext struct { + // IncludeDeclaration include the declaration of the current symbol. + IncludeDeclaration bool `json:"includeDeclaration"` +} + +// DocumentHighlight a document highlight is a range inside a text document which deserves +// special attention. Usually a document highlight is visualized by changing +// the background color of its range. +type DocumentHighlight struct { + // Range is the range this highlight applies to. + Range Range `json:"range"` + + // Kind is the highlight kind, default is DocumentHighlightKind.Text. + Kind DocumentHighlightKind `json:"kind,omitempty"` +} + +// DocumentHighlightKind a document highlight kind. +type DocumentHighlightKind float64 + +const ( + // DocumentHighlightKindText a textual occurrence. + DocumentHighlightKindText DocumentHighlightKind = 1 + + // DocumentHighlightKindRead read-access of a symbol, like reading a variable. + DocumentHighlightKindRead DocumentHighlightKind = 2 + + // DocumentHighlightKindWrite write-access of a symbol, like writing to a variable. + DocumentHighlightKindWrite DocumentHighlightKind = 3 +) + +// String implements fmt.Stringer. +func (k DocumentHighlightKind) String() string { + switch k { + case DocumentHighlightKindText: + return "Text" + case DocumentHighlightKindRead: + return "Read" + case DocumentHighlightKindWrite: + return "Write" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// DocumentSymbolParams params of Document Symbols request. +type DocumentSymbolParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// SymbolKind specific capabilities for the `SymbolKind`. +// The symbol kind values the client supports. When this +// property exists the client also guarantees that it will +// handle values outside its set gracefully and falls back +// to a default value when unknown. +// +// If this property is not present the client only supports +// the symbol kinds from `File` to `Array` as defined in +// the initial version of the protocol. +type SymbolKind float64 + +const ( + // SymbolKindFile symbol of file. + SymbolKindFile SymbolKind = 1 + // SymbolKindModule symbol of module. + SymbolKindModule SymbolKind = 2 + // SymbolKindNamespace symbol of namespace. + SymbolKindNamespace SymbolKind = 3 + // SymbolKindPackage symbol of package. + SymbolKindPackage SymbolKind = 4 + // SymbolKindClass symbol of class. + SymbolKindClass SymbolKind = 5 + // SymbolKindMethod symbol of method. + SymbolKindMethod SymbolKind = 6 + // SymbolKindProperty symbol of property. + SymbolKindProperty SymbolKind = 7 + // SymbolKindField symbol of field. + SymbolKindField SymbolKind = 8 + // SymbolKindConstructor symbol of constructor. + SymbolKindConstructor SymbolKind = 9 + // SymbolKindEnum symbol of enum. + SymbolKindEnum SymbolKind = 10 + // SymbolKindInterface symbol of interface. + SymbolKindInterface SymbolKind = 11 + // SymbolKindFunction symbol of function. + SymbolKindFunction SymbolKind = 12 + // SymbolKindVariable symbol of variable. + SymbolKindVariable SymbolKind = 13 + // SymbolKindConstant symbol of constant. + SymbolKindConstant SymbolKind = 14 + // SymbolKindString symbol of string. + SymbolKindString SymbolKind = 15 + // SymbolKindNumber symbol of number. + SymbolKindNumber SymbolKind = 16 + // SymbolKindBoolean symbol of boolean. + SymbolKindBoolean SymbolKind = 17 + // SymbolKindArray symbol of array. + SymbolKindArray SymbolKind = 18 + // SymbolKindObject symbol of object. + SymbolKindObject SymbolKind = 19 + // SymbolKindKey symbol of key. + SymbolKindKey SymbolKind = 20 + // SymbolKindNull symbol of null. + SymbolKindNull SymbolKind = 21 + // SymbolKindEnumMember symbol of enum member. + SymbolKindEnumMember SymbolKind = 22 + // SymbolKindStruct symbol of struct. + SymbolKindStruct SymbolKind = 23 + // SymbolKindEvent symbol of event. + SymbolKindEvent SymbolKind = 24 + // SymbolKindOperator symbol of operator. + SymbolKindOperator SymbolKind = 25 + // SymbolKindTypeParameter symbol of type parameter. + SymbolKindTypeParameter SymbolKind = 26 +) + +// String implements fmt.Stringer. +// +//nolint:cyclop +func (k SymbolKind) String() string { + switch k { + case SymbolKindFile: + return "File" + case SymbolKindModule: + return "Module" + case SymbolKindNamespace: + return "Namespace" + case SymbolKindPackage: + return "Package" + case SymbolKindClass: + return "Class" + case SymbolKindMethod: + return "Method" + case SymbolKindProperty: + return "Property" + case SymbolKindField: + return "Field" + case SymbolKindConstructor: + return "Constructor" + case SymbolKindEnum: + return "Enum" + case SymbolKindInterface: + return "Interface" + case SymbolKindFunction: + return "Function" + case SymbolKindVariable: + return "Variable" + case SymbolKindConstant: + return "Constant" + case SymbolKindString: + return "String" + case SymbolKindNumber: + return "Number" + case SymbolKindBoolean: + return "Boolean" + case SymbolKindArray: + return "Array" + case SymbolKindObject: + return "Object" + case SymbolKindKey: + return "Key" + case SymbolKindNull: + return "Null" + case SymbolKindEnumMember: + return "EnumMember" + case SymbolKindStruct: + return "Struct" + case SymbolKindEvent: + return "Event" + case SymbolKindOperator: + return "Operator" + case SymbolKindTypeParameter: + return "TypeParameter" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// SymbolTag symbol tags are extra annotations that tweak the rendering of a symbol. +// +// @since 3.16.0. +type SymbolTag float64 + +// list of SymbolTag. +const ( + // SymbolTagDeprecated render a symbol as obsolete, usually using a strike-out. + SymbolTagDeprecated SymbolTag = 1 +) + +// String returns a string representation of the SymbolTag. +func (k SymbolTag) String() string { + switch k { + case SymbolTagDeprecated: + return "Deprecated" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// DocumentSymbol represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document symbols can be +// hierarchical and they have two ranges: one that encloses its definition and one that points to its most interesting range, +// e.g. the range of an identifier. +type DocumentSymbol struct { + // Name is the name of this symbol. Will be displayed in the user interface and therefore must not be + // an empty string or a string only consisting of white spaces. + Name string `json:"name"` + + // Detail is the more detail for this symbol, e.g the signature of a function. + Detail string `json:"detail,omitempty"` + + // Kind is the kind of this symbol. + Kind SymbolKind `json:"kind"` + + // Tags for this document symbol. + // + // @since 3.16.0. + Tags []SymbolTag `json:"tags,omitempty"` + + // Deprecated indicates if this symbol is deprecated. + Deprecated bool `json:"deprecated,omitempty"` + + // Range is the range enclosing this symbol not including leading/trailing whitespace but everything else + // like comments. This information is typically used to determine if the clients cursor is + // inside the symbol to reveal in the symbol in the UI. + Range Range `json:"range"` + + // SelectionRange is the range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + // Must be contained by the `range`. + SelectionRange Range `json:"selectionRange"` + + // Children children of this symbol, e.g. properties of a class. + Children []DocumentSymbol `json:"children,omitempty"` +} + +// SymbolInformation represents information about programming constructs like variables, classes, +// interfaces etc. +type SymbolInformation struct { + // Name is the name of this symbol. + Name string `json:"name"` + + // Kind is the kind of this symbol. + Kind SymbolKind `json:"kind"` + + // Tags for this completion item. + // + // @since 3.16.0. + Tags []SymbolTag `json:"tags,omitempty"` + + // Deprecated indicates if this symbol is deprecated. + Deprecated bool `json:"deprecated,omitempty"` + + // Location is the location of this symbol. The location's range is used by a tool + // to reveal the location in the editor. If the symbol is selected in the + // tool the range's start information is used to position the cursor. So + // the range usually spans more then the actual symbol's name and does + // normally include things like visibility modifiers. + // + // The range doesn't have to denote a node range in the sense of a abstract + // syntax tree. It can therefore not be used to re-construct a hierarchy of + // the symbols. + Location Location `json:"location"` + + // ContainerName is the name of the symbol containing this symbol. This information is for + // user interface purposes (e.g. to render a qualifier in the user interface + // if necessary). It can't be used to re-infer a hierarchy for the document + // symbols. + ContainerName string `json:"containerName,omitempty"` +} + +type SymbolInformationOrDocumentSymbol struct { + SymbolInformation *SymbolInformation + DocumentSymbol *DocumentSymbol +} + +func (s *SymbolInformationOrDocumentSymbol) MarshalJSON() ([]byte, error) { + if s.SymbolInformation != nil { + return json.Marshal(s.SymbolInformation) + } + return json.Marshal(s.DocumentSymbol) +} + +func (s *SymbolInformationOrDocumentSymbol) UnmarshalJSON(data []byte) error { + var si SymbolInformation + if err := json.Unmarshal(data, &si); err != nil { + return err + } + s.SymbolInformation = &si + + var ds DocumentSymbol + err := json.Unmarshal(data, &ds) + if err != nil { + return err + } + s.DocumentSymbol = &ds + + // Only SymbolInformation has a location URI. + if s.SymbolInformation.Location.URI == "" { + s.SymbolInformation = nil + } else { + s.DocumentSymbol = nil + } + + return nil +} + +// CodeActionParams params for the CodeActionRequest. +type CodeActionParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the document in which the command was invoked. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Context carrying additional information. + Context CodeActionContext `json:"context"` + + // Range is the range for which the command was invoked. + Range Range `json:"range"` +} + +// CodeActionKind is the code action kind values the client supports. When this +// property exists the client also guarantees that it will +// handle values outside its set gracefully and falls back +// to a default value when unknown. +type CodeActionKind string + +// A set of predefined code action kinds. +const ( + // QuickFix base kind for quickfix actions: 'quickfix'. + QuickFix CodeActionKind = "quickfix" + + // Refactor base kind for refactoring actions: 'refactor'. + Refactor CodeActionKind = "refactor" + + // RefactorExtract base kind for refactoring extraction actions: 'refactor.extract' + // + // Example extract actions: + // + // - Extract method + // - Extract function + // - Extract variable + // - Extract interface from class + // - ... + RefactorExtract CodeActionKind = "refactor.extract" + + // RefactorInline base kind for refactoring inline actions: 'refactor.inline' + // + // Example inline actions: + // + // - Inline function + // - Inline variable + // - Inline constant + // - ... + RefactorInline CodeActionKind = "refactor.inline" + + // RefactorRewrite base kind for refactoring rewrite actions: 'refactor.rewrite' + // + // Example rewrite actions: + // + // - Convert JavaScript function to class + // - Add or remove parameter + // - Encapsulate field + // - Make method static + // - Move method to base class + // - ... + RefactorRewrite CodeActionKind = "refactor.rewrite" + + // Source base kind for source actions: `source` + // + // Source code actions apply to the entire file. + Source CodeActionKind = "source" + + // SourceOrganizeImports base kind for an organize imports source action: `source.organizeImports`. + SourceOrganizeImports CodeActionKind = "source.organizeImports" +) + +// CodeActionContext contains additional diagnostic information about the context in which +// a code action is run. +type CodeActionContext struct { + // Diagnostics is an array of diagnostics. + Diagnostics []Diagnostic `json:"diagnostics"` + + // Only requested kind of actions to return. + // + // Actions not of this kind are filtered out by the client before being shown. So servers + // can omit computing them. + Only []CodeActionKind `json:"only,omitempty"` +} + +// CodeAction capabilities specific to the `textDocument/codeAction`. +type CodeAction struct { + // Title is a short, human-readable, title for this code action. + Title string `json:"title"` + + // Kind is the kind of the code action. + // + // Used to filter code actions. + Kind CodeActionKind `json:"kind,omitempty"` + + // Diagnostics is the diagnostics that this code action resolves. + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + + // IsPreferred marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + // by keybindings. + // + // A quick fix should be marked preferred if it properly addresses the underlying error. + // A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + // + // @since 3.15.0. + IsPreferred bool `json:"isPreferred,omitempty"` + + // Disabled marks that the code action cannot currently be applied. + // + // Clients should follow the following guidelines regarding disabled code + // actions: + // + // - Disabled code actions are not shown in automatic lightbulbs code + // action menus. + // + // - Disabled actions are shown as faded out in the code action menu when + // the user request a more specific type of code action, such as + // refactorings. + // + // - If the user has a keybinding that auto applies a code action and only + // a disabled code actions are returned, the client should show the user + // an error message with `reason` in the editor. + // + // @since 3.16.0. + Disabled *CodeActionDisable `json:"disabled,omitempty"` + + // Edit is the workspace edit this code action performs. + Edit *WorkspaceEdit `json:"edit,omitempty"` + + // Command is a command this code action executes. If a code action + // provides an edit and a command, first the edit is + // executed and then the command. + Command *Command `json:"command,omitempty"` + + // Data is a data entry field that is preserved on a code action between + // a "textDocument/codeAction" and a "codeAction/resolve" request. + // + // @since 3.16.0. + Data any `json:"data,omitempty"` +} + +// CodeActionDisable Disable in CodeAction. +// +// @since 3.16.0. +type CodeActionDisable struct { + // Reason human readable description of why the code action is currently + // disabled. + // + // This is displayed in the code actions UI. + Reason string `json:"reason"` +} + +// CodeActionRegistrationOptions CodeAction Registrationi options. +type CodeActionRegistrationOptions struct { + TextDocumentRegistrationOptions + + CodeActionOptions +} + +// CodeLensParams params of Code Lens request. +type CodeLensParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the document to request code lens for. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// CodeLens is a code lens represents a command that should be shown along with +// source text, like the number of references, a way to run tests, etc. +// +// A code lens is _unresolved_ when no command is associated to it. For performance +// reasons the creation of a code lens and resolving should be done in two stages. +type CodeLens struct { + // Range is the range in which this code lens is valid. Should only span a single line. + Range Range `json:"range"` + + // Command is the command this code lens represents. + Command *Command `json:"command,omitempty"` + + // Data is a data entry field that is preserved on a code lens item between + // a code lens and a code lens resolve request. + Data any `json:"data,omitempty"` +} + +// CodeLensRegistrationOptions CodeLens Registration options. +type CodeLensRegistrationOptions struct { + TextDocumentRegistrationOptions + + // ResolveProvider code lens has a resolve provider as well. + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +// DocumentLinkParams params of Document Link request. +type DocumentLinkParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the document to provide document links for. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// DocumentLink is a document link is a range in a text document that links to an internal or external resource, like another +// text document or a web site. +type DocumentLink struct { + // Range is the range this link applies to. + Range Range `json:"range"` + + // Target is the uri this link points to. If missing a resolve request is sent later. + Target DocumentURI `json:"target,omitempty"` + + // Tooltip is the tooltip text when you hover over this link. + // + // If a tooltip is provided, is will be displayed in a string that includes instructions on how to + // trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + // user settings, and localization. + // + // @since 3.15.0. + Tooltip string `json:"tooltip,omitempty"` + + // Data is a data entry field that is preserved on a document link between a + // DocumentLinkRequest and a DocumentLinkResolveRequest. + Data any `json:"data,omitempty"` +} + +// DocumentColorParams params of Document Color request. +type DocumentColorParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the document to format. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// ColorInformation response of Document Color request. +type ColorInformation struct { + // Range is the range in the document where this color appears. + Range Range `json:"range"` + + // Color is the actual color value for this color range. + Color Color `json:"color"` +} + +// Color represents a color in RGBA space. +type Color struct { + // Alpha is the alpha component of this color in the range [0-1]. + Alpha float64 `json:"alpha"` + + // Blue is the blue component of this color in the range [0-1]. + Blue float64 `json:"blue"` + + // Green is the green component of this color in the range [0-1]. + Green float64 `json:"green"` + + // Red is the red component of this color in the range [0-1]. + Red float64 `json:"red"` +} + +// ColorPresentationParams params of Color Presentation request. +type ColorPresentationParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Color is the color information to request presentations for. + Color Color `json:"color"` + + // Range is the range where the color would be inserted. Serves as a context. + Range Range `json:"range"` +} + +// ColorPresentation response of Color Presentation request. +type ColorPresentation struct { + // Label is the label of this color presentation. It will be shown on the color + // picker header. By default this is also the text that is inserted when selecting + // this color presentation. + Label string `json:"label"` + + // TextEdit an edit which is applied to a document when selecting + // this presentation for the color. When `falsy` the label is used. + TextEdit *TextEdit `json:"textEdit,omitempty"` + + // AdditionalTextEdits an optional array of additional [text edits](#TextEdit) that are applied when + // selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` +} + +// DocumentFormattingParams params of Document Formatting request. +type DocumentFormattingParams struct { + WorkDoneProgressParams + + // Options is the format options. + Options FormattingOptions `json:"options"` + + // TextDocument is the document to format. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// FormattingOptions value-object describing what options formatting should use. +type FormattingOptions struct { + // InsertSpaces prefer spaces over tabs. + InsertSpaces bool `json:"insertSpaces"` + + // TabSize size of a tab in spaces. + TabSize uint32 `json:"tabSize"` + + // TrimTrailingWhitespace trim trailing whitespaces on a line. + // + // @since 3.15.0. + TrimTrailingWhitespace bool `json:"trimTrailingWhitespace,omitempty"` + + // InsertFinalNewlines insert a newline character at the end of the file if one does not exist. + // + // @since 3.15.0. + InsertFinalNewline bool `json:"insertFinalNewline,omitempty"` + + // TrimFinalNewlines trim all newlines after the final newline at the end of the file. + // + // @since 3.15.0. + TrimFinalNewlines bool `json:"trimFinalNewlines,omitempty"` + + // Key is the signature for further properties. + Key map[string]any `json:"key,omitempty"` // bool | int32 | string +} + +// DocumentRangeFormattingParams params of Document Range Formatting request. +type DocumentRangeFormattingParams struct { + WorkDoneProgressParams + + // TextDocument is the document to format. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Range is the range to format + Range Range `json:"range"` + + // Options is the format options. + Options FormattingOptions `json:"options"` +} + +// DocumentOnTypeFormattingParams params of Document on Type Formatting request. +type DocumentOnTypeFormattingParams struct { + // TextDocument is the document to format. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Position is the position at which this request was sent. + Position Position `json:"position"` + + // Ch is the character that has been typed. + Ch string `json:"ch"` + + // Options is the format options. + Options FormattingOptions `json:"options"` +} + +// DocumentOnTypeFormattingRegistrationOptions DocumentOnTypeFormatting Registration options. +type DocumentOnTypeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + + // FirstTriggerCharacter a character on which formatting should be triggered, like `}`. + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + + // MoreTriggerCharacter a More trigger characters. + MoreTriggerCharacter []string `json:"moreTriggerCharacter"` +} + +// RenameParams params of Rename request. +type RenameParams struct { + TextDocumentPositionParams + PartialResultParams + + // NewName is the new name of the symbol. If the given name is not valid the + // request must return a [ResponseError](#ResponseError) with an + // appropriate message set. + NewName string `json:"newName"` +} + +// RenameRegistrationOptions Rename Registration options. +type RenameRegistrationOptions struct { + TextDocumentRegistrationOptions + + // PrepareProvider is the renames should be checked and tested for validity before being executed. + PrepareProvider bool `json:"prepareProvider,omitempty"` +} + +// PrepareRenameParams params of PrepareRenameParams request. +// +// @since 3.15.0. +type PrepareRenameParams struct { + TextDocumentPositionParams +} + +// FoldingRangeParams params of Folding Range request. +type FoldingRangeParams struct { + TextDocumentPositionParams + PartialResultParams +} + +// FoldingRangeKind is the enum of known range kinds. +type FoldingRangeKind string + +const ( + // CommentFoldingRange is the folding range for a comment. + CommentFoldingRange FoldingRangeKind = "comment" + + // ImportsFoldingRange is the folding range for a imports or includes. + ImportsFoldingRange FoldingRangeKind = "imports" + + // RegionFoldingRange is the folding range for a region (e.g. `#region`). + RegionFoldingRange FoldingRangeKind = "region" +) + +// FoldingRange capabilities specific to `textDocument/foldingRange` requests. +// +// @since 3.10.0. +type FoldingRange struct { + // StartLine is the zero-based line number from where the folded range starts. + StartLine uint32 `json:"startLine"` + + // StartCharacter is the zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + StartCharacter uint32 `json:"startCharacter,omitempty"` + + // EndLine is the zero-based line number where the folded range ends. + EndLine uint32 `json:"endLine"` + + // EndCharacter is the zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + EndCharacter uint32 `json:"endCharacter,omitempty"` + + // Kind describes the kind of the folding range such as `comment' or 'region'. The kind + // is used to categorize folding ranges and used by commands like 'Fold all comments'. + // See FoldingRangeKind for an enumeration of standardized kinds. + Kind FoldingRangeKind `json:"kind,omitempty"` +} diff --git a/templ/lsp/protocol/language_test.go b/templ/lsp/protocol/language_test.go new file mode 100644 index 0000000..e2497d7 --- /dev/null +++ b/templ/lsp/protocol/language_test.go @@ -0,0 +1,6060 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "bytes" + "fmt" + "strings" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/a-h/templ/lsp/uri" +) + +func TestCompletionParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","context":{"triggerCharacter":".","triggerKind":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":2,"character":0},"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","context":{"triggerCharacter":".","triggerKind":1}}` + ) + wantType := CompletionParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + Context: &CompletionContext{ + TriggerCharacter: ".", + TriggerKind: CompletionTriggerKindInvoked, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CompletionParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CompletionParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCompletionTriggerKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k CompletionTriggerKind + want string + }{ + { + name: "Invoked", + k: CompletionTriggerKindInvoked, + want: "Invoked", + }, + { + name: "TriggerCharacter", + k: CompletionTriggerKindTriggerCharacter, + want: "TriggerCharacter", + }, + { + name: "TriggerForIncompleteCompletions", + k: CompletionTriggerKindTriggerForIncompleteCompletions, + want: "TriggerForIncompleteCompletions", + }, + { + name: "Unknown", + k: CompletionTriggerKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("CompletionTriggerKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestCompletionContext(t *testing.T) { + t.Parallel() + + const ( + want = `{"triggerCharacter":".","triggerKind":1}` + wantInvalid = `{"triggerCharacter":" ","triggerKind":0}` + ) + wantType := CompletionContext{ + TriggerCharacter: ".", + TriggerKind: CompletionTriggerKindInvoked, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CompletionContext + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CompletionContext + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionContext + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCompletionList(t *testing.T) { + t.Parallel() + + const ( + want = `{"isIncomplete":true,"items":[{"tags":[1],"detail":"string","documentation":"Detail a human-readable string with additional information about this item, like type or symbol information.","filterText":"Detail","insertTextFormat":2,"kind":5,"label":"Detail","preselect":true,"sortText":"00000","textEdit":{"range":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}},"newText":"Detail: ${1:},"}}]}` + wantInvalid = `{"isIncomplete":false,"items":[]}` + ) + wantType := CompletionList{ + IsIncomplete: true, + Items: []CompletionItem{ + { + AdditionalTextEdits: nil, + Command: nil, + CommitCharacters: nil, + Tags: []CompletionItemTag{ + CompletionItemTagDeprecated, + }, + Deprecated: false, + Detail: "string", + Documentation: "Detail a human-readable string with additional information about this item, like type or symbol information.", + FilterText: "Detail", + InsertText: "", + InsertTextFormat: InsertTextFormatSnippet, + Kind: CompletionItemKindField, + Label: "Detail", + Preselect: true, + SortText: "00000", + TextEdit: &TextEditOrInsertReplaceEdit{ + TextEdit: &TextEdit{ + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + NewText: "Detail: ${1:},", + }, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CompletionList + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CompletionList + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionList + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestInsertTextFormat_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k InsertTextFormat + want string + }{ + { + name: "PlainText", + k: InsertTextFormatPlainText, + want: "PlainText", + }, + { + name: "Snippet", + k: InsertTextFormatSnippet, + want: "Snippet", + }, + { + name: "Unknown", + k: InsertTextFormat(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("InsertTextFormat.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestInsertReplaceEdit(t *testing.T) { + t.Parallel() + + const ( + want = `{"newText":"testNewText","insert":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}},"replace":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}}}` + ) + wantType := InsertReplaceEdit{ + NewText: "testNewText", + Insert: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + Replace: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field InsertReplaceEdit + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want InsertReplaceEdit + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got InsertReplaceEdit + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestInsertTextMode_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k InsertTextMode + want string + }{ + { + name: "AsIs", + k: InsertTextModeAsIs, + want: "AsIs", + }, + { + name: "AdjustIndentation", + k: InsertTextModeAdjustIndentation, + want: "AdjustIndentation", + }, + { + name: "Unknown", + k: InsertTextMode(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("InsertTextMode.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestCompletionItem(t *testing.T) { + t.Parallel() + + const ( + wantTextEdit = `{ + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 255, + "character": 4 + }, + "end": { + "line": 255, + "character": 10 + } + }, + "newText": "Detail: ${1:}," + } + ], + "command": { + "title": "exec echo", + "command": "echo", + "arguments": [ + "hello" + ] + }, + "commitCharacters": [ + "a" + ], + "tags": [ + 1 + ], + "data": "testData", + "deprecated": true, + "detail": "string", + "documentation": "Detail a human-readable string with additional information about this item, like type or symbol information.", + "filterText": "Detail", + "insertText": "testInsert", + "insertTextFormat": 2, + "insertTextMode": 1, + "kind": 5, + "label": "Detail", + "preselect": true, + "sortText": "00000", + "textEdit": { + "range": { + "start": { + "line": 255, + "character": 4 + }, + "end": { + "line": 255, + "character": 10 + } + }, + "newText": "Detail: ${1:}," + } +}` + wantInsertReplaceEdit = `{ + "additionalTextEdits": [ + { + "range": { + "start": { + "line": 255, + "character": 4 + }, + "end": { + "line": 255, + "character": 10 + } + }, + "newText": "Detail: ${1:}," + } + ], + "command": { + "title": "exec echo", + "command": "echo", + "arguments": [ + "hello" + ] + }, + "commitCharacters": [ + "a" + ], + "tags": [ + 1 + ], + "data": "testData", + "deprecated": true, + "detail": "string", + "documentation": "Detail a human-readable string with additional information about this item, like type or symbol information.", + "filterText": "Detail", + "insertText": "testInsert", + "insertTextFormat": 2, + "insertTextMode": 1, + "kind": 5, + "label": "Detail", + "preselect": true, + "sortText": "00000", + "textEdit": { + "newText": "Detail: ${1:},", + "insert": { + "start": { + "line": 105, + "character": 65 + }, + "end": { + "line": 105, + "character": 72 + } + }, + "replace": { + "start": { + "line": 105, + "character": 65 + }, + "end": { + "line": 105, + "character": 76 + } + } + } +}` + wantNilAll = `{ + "label": "Detail" +}` + wantInvalid = `{"items":[]}` + ) + wantTypeTextEdit := CompletionItem{ + AdditionalTextEdits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + NewText: "Detail: ${1:},", + }, + }, + Command: &Command{ + Title: "exec echo", + Command: "echo", + Arguments: []any{"hello"}, + }, + CommitCharacters: []string{"a"}, + Tags: []CompletionItemTag{ + CompletionItemTagDeprecated, + }, + Data: "testData", + Deprecated: true, + Detail: "string", + Documentation: "Detail a human-readable string with additional information about this item, like type or symbol information.", + FilterText: "Detail", + InsertText: "testInsert", + InsertTextFormat: InsertTextFormatSnippet, + InsertTextMode: InsertTextModeAsIs, + Kind: CompletionItemKindField, + Label: "Detail", + Preselect: true, + SortText: "00000", + TextEdit: &TextEditOrInsertReplaceEdit{ + TextEdit: &TextEdit{ + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + NewText: "Detail: ${1:},", + }, + }, + } + wantTypeInsertReplaceEdit := CompletionItem{ + AdditionalTextEdits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + NewText: "Detail: ${1:},", + }, + }, + Command: &Command{ + Title: "exec echo", + Command: "echo", + Arguments: []any{"hello"}, + }, + CommitCharacters: []string{"a"}, + Tags: []CompletionItemTag{ + CompletionItemTagDeprecated, + }, + Data: "testData", + Deprecated: true, + Detail: "string", + Documentation: "Detail a human-readable string with additional information about this item, like type or symbol information.", + FilterText: "Detail", + InsertText: "testInsert", + InsertTextFormat: InsertTextFormatSnippet, + InsertTextMode: InsertTextModeAsIs, + Kind: CompletionItemKindField, + Label: "Detail", + Preselect: true, + SortText: "00000", + TextEdit: &TextEditOrInsertReplaceEdit{ + InsertReplaceEdit: &InsertReplaceEdit{ + NewText: "Detail: ${1:},", + Insert: Range{ + Start: Position{ + Line: 105, + Character: 65, + }, + End: Position{ + Line: 105, + Character: 72, + }, + }, + Replace: Range{ + Start: Position{ + Line: 105, + Character: 65, + }, + End: Position{ + Line: 105, + Character: 76, + }, + }, + }, + }, + } + wantTypeNilAll := CompletionItem{ + Label: "Detail", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CompletionItem + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "ValidTextEdit", + field: wantTypeTextEdit, + want: wantTextEdit, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidInsertReplaceEdit", + field: wantTypeInsertReplaceEdit, + want: wantInsertReplaceEdit, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantTypeTextEdit, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + b := new(bytes.Buffer) + enc := json.NewEncoder(b) + enc.SetIndent("", " ") + err := enc.Encode(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + got := strings.TrimSpace(b.String()) + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CompletionItem + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "ValidTextEdit", + field: wantTextEdit, + want: wantTypeTextEdit, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidInsertReplaceEdit", + field: wantInsertReplaceEdit, + want: wantTypeInsertReplaceEdit, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantTypeTextEdit, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionItem + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCompletionItemKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k CompletionItemKind + want string + }{ + { + name: "Text", + k: CompletionItemKindText, + want: "Text", + }, + { + name: "Method", + k: CompletionItemKindMethod, + want: "Method", + }, + { + name: "Function", + k: CompletionItemKindFunction, + want: "Function", + }, + { + name: "Constructor", + k: CompletionItemKindConstructor, + want: "Constructor", + }, + { + name: "Field", + k: CompletionItemKindField, + want: "Field", + }, + { + name: "Variable", + k: CompletionItemKindVariable, + want: "Variable", + }, + { + name: "Class", + k: CompletionItemKindClass, + want: "Class", + }, + { + name: "Interface", + k: CompletionItemKindInterface, + want: "Interface", + }, + { + name: "Module", + k: CompletionItemKindModule, + want: "Module", + }, + { + name: "Property", + k: CompletionItemKindProperty, + want: "Property", + }, + { + name: "Unit", + k: CompletionItemKindUnit, + want: "Unit", + }, + { + name: "Value", + k: CompletionItemKindValue, + want: "Value", + }, + { + name: "Enum", + k: CompletionItemKindEnum, + want: "Enum", + }, + { + name: "Keyword", + k: CompletionItemKindKeyword, + want: "Keyword", + }, + { + name: "Snippet", + k: CompletionItemKindSnippet, + want: "Snippet", + }, + { + name: "Color", + k: CompletionItemKindColor, + want: "Color", + }, + { + name: "File", + k: CompletionItemKindFile, + want: "File", + }, + { + name: "Reference", + k: CompletionItemKindReference, + want: "Reference", + }, + { + name: "Folder", + k: CompletionItemKindFolder, + want: "Folder", + }, + { + name: "EnumMember", + k: CompletionItemKindEnumMember, + want: "EnumMember", + }, + { + name: "Constant", + k: CompletionItemKindConstant, + want: "Constant", + }, + { + name: "Struct", + k: CompletionItemKindStruct, + want: "Struct", + }, + { + name: "Event", + k: CompletionItemKindEvent, + want: "Event", + }, + { + name: "Operator", + k: CompletionItemKindOperator, + want: "Operator", + }, + { + name: "TypeParameter", + k: CompletionItemKindTypeParameter, + want: "TypeParameter", + }, + { + name: "Unknown", + k: CompletionItemKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("CompletionItemKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestCompletionItemTag_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k CompletionItemTag + want string + }{ + { + name: "Deprecated", + k: CompletionItemTagDeprecated, + want: "Deprecated", + }, + { + name: "Unknown", + k: CompletionItemTag(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("CompletionItemTag.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestCompletionRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"triggerCharacters":["."],"resolveProvider":true}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"triggerCharacters":[" "],"resolveProvider":true}` + ) + wantType := CompletionRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + TriggerCharacters: []string{"."}, + ResolveProvider: true, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CompletionRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CompletionRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CompletionRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestHoverParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `"}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + invalidWorkDoneToken + `"}` + ) + wantType := HoverParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + } + wantTypeNilAll := HoverParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field HoverParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want HoverParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got HoverParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestHover(t *testing.T) { + t.Parallel() + + const ( + want = `{"contents":{"kind":"markdown","value":"example value"},"range":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}}}` + wantInvalid = `{"contents":{"kind":"markdown","value":"example value"},"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":5}}}` + ) + wantType := Hover{ + Contents: MarkupContent{ + Kind: Markdown, + Value: "example value", + }, + Range: &Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Hover + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Hover + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Hover + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSignatureHelpParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1},"workDoneToken":"` + wantWorkDoneToken + `","context":{"triggerKind":1,"triggerCharacter":".","isRetrigger":true,"activeSignatureHelp":{"signatures":[{"label":"testLabel","documentation":"testDocumentation","parameters":[{"label":"test label","documentation":"test documentation"}]}],"activeParameter":10,"activeSignature":5}}}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/basic.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go"},"position":{"line":2,"character":1},"workDoneToken":"` + invalidWorkDoneToken + `","context":{"triggerKind":0,"triggerCharacter":"aaa","isRetrigger":false,"activeSignatureHelp":{"signatures":[{"documentationFormat":["markdown"],"parameterInformation":{"label":"test label","documentation":"test documentation"}}],"activeParameter":1,"activeSignature":0}}}` + ) + wantType := SignatureHelpParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + Context: &SignatureHelpContext{ + TriggerKind: SignatureHelpTriggerKindInvoked, + TriggerCharacter: ".", + IsRetrigger: true, + ActiveSignatureHelp: &SignatureHelp{ + Signatures: []SignatureInformation{ + { + Label: "testLabel", + Documentation: "testDocumentation", + Parameters: []ParameterInformation{ + { + Label: "test label", + Documentation: "test documentation", + }, + }, + }, + }, + ActiveParameter: 10, + ActiveSignature: 5, + }, + }, + } + wantTypeNilAll := SignatureHelpParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field SignatureHelpParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want SignatureHelpParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SignatureHelpParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestSignatureHelpTriggerKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k SignatureHelpTriggerKind + want string + }{ + { + name: "Invoked", + k: SignatureHelpTriggerKindInvoked, + want: "Invoked", + }, + { + name: "TriggerCharacter", + k: SignatureHelpTriggerKindTriggerCharacter, + want: "TriggerCharacter", + }, + { + name: "ContentChange", + k: SignatureHelpTriggerKindContentChange, + want: "ContentChange", + }, + { + name: "Unknown", + k: SignatureHelpTriggerKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("SignatureHelpTriggerKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestSignatureHelp(t *testing.T) { + t.Parallel() + + const ( + want = `{"signatures":[{"label":"testLabel","documentation":"testDocumentation","parameters":[{"label":"test label","documentation":"test documentation"}]}],"activeParameter":10,"activeSignature":5}` + wantNilAll = `{"signatures":[]}` + wantInvalid = `{"signatures":[{"label":"invalidLabel","documentation":"invalidDocumentation","parameters":[{"label":"test label","documentation":"test documentation"}]}],"activeParameter":1,"activeSignature":0}` + ) + wantType := SignatureHelp{ + Signatures: []SignatureInformation{ + { + Label: "testLabel", + Documentation: "testDocumentation", + Parameters: []ParameterInformation{ + { + Label: "test label", + Documentation: "test documentation", + }, + }, + }, + }, + ActiveParameter: 10, + ActiveSignature: 5, + } + wantTypeNilAll := SignatureHelp{ + Signatures: []SignatureInformation{}, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field SignatureHelp + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want SignatureHelp + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SignatureHelp + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSignatureInformation(t *testing.T) { + t.Parallel() + + const ( + want = `{"label":"testLabel","documentation":"testDocumentation","parameters":[{"label":"test label","documentation":"test documentation"}],"activeParameter":5}` + wantInvalid = `{"label":"testLabel","documentation":"invalidDocumentation","parameters":[{"label":"test label","documentation":"test documentation"}],"activeParameter":50}` + ) + wantType := SignatureInformation{ + Label: "testLabel", + Documentation: "testDocumentation", + Parameters: []ParameterInformation{ + { + Label: "test label", + Documentation: "test documentation", + }, + }, + ActiveParameter: uint32(5), + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field SignatureInformation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want SignatureInformation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SignatureInformation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestParameterInformation(t *testing.T) { + t.Parallel() + + const ( + want = `{"label":"test label","documentation":"test documentation"}` + wantInvalid = `{"label":"invalid","documentation":"invalid"}` + ) + wantType := ParameterInformation{ + Label: "test label", + Documentation: "test documentation", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ParameterInformation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ParameterInformation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ParameterInformation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSignatureHelpRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"triggerCharacters":["."]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"triggerCharacters":[" "]}` + ) + wantType := SignatureHelpRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + TriggerCharacters: []string{"."}, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field SignatureHelpRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want SignatureHelpRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SignatureHelpRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestReferenceParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1},"context":{"includeDeclaration":true}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":2,"character":0},"context":{"includeDeclaration":false}}` + ) + wantType := ReferenceParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + Context: ReferenceContext{ + IncludeDeclaration: true, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ReferenceParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ReferenceParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ReferenceParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestReferenceContext(t *testing.T) { + t.Parallel() + + const ( + want = `{"includeDeclaration":true}` + wantInvalid = `{"includeDeclaration":false}` + ) + wantType := ReferenceContext{ + IncludeDeclaration: true, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ReferenceContext + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ReferenceContext + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ReferenceContext + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentHighlight(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}},"kind":1}` + wantInvalid = `{"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":5}},"kind":1}` + ) + wantType := DocumentHighlight{ + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + Kind: DocumentHighlightKindText, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentHighlight + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentHighlight + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentHighlight + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentHighlightKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k DocumentHighlightKind + want string + }{ + { + name: "Text", + k: DocumentHighlightKindText, + want: "Text", + }, + { + name: "Read", + k: DocumentHighlightKindRead, + want: "Read", + }, + { + name: "Write", + k: DocumentHighlightKindWrite, + want: "Write", + }, + { + name: "Unknown", + k: DocumentHighlightKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("DocumentHighlightKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestDocumentSymbolParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + wantType := DocumentSymbolParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/nottest.go"}}` + ) + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentSymbolParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentSymbolParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentSymbolParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestSymbolKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k SymbolKind + want string + }{ + { + name: "File", + k: SymbolKindFile, + want: "File", + }, + { + name: "Module", + k: SymbolKindModule, + want: "Module", + }, + { + name: "Namespace", + k: SymbolKindNamespace, + want: "Namespace", + }, + { + name: "Package", + k: SymbolKindPackage, + want: "Package", + }, + { + name: "Class", + k: SymbolKindClass, + want: "Class", + }, + { + name: "Method", + k: SymbolKindMethod, + want: "Method", + }, + { + name: "Property", + k: SymbolKindProperty, + want: "Property", + }, + { + name: "Field", + k: SymbolKindField, + want: "Field", + }, + { + name: "Constructor", + k: SymbolKindConstructor, + want: "Constructor", + }, + { + name: "Enum", + k: SymbolKindEnum, + want: "Enum", + }, + { + name: "Interface", + k: SymbolKindInterface, + want: "Interface", + }, + { + name: "Function", + k: SymbolKindFunction, + want: "Function", + }, + { + name: "Variable", + k: SymbolKindVariable, + want: "Variable", + }, + { + name: "Constant", + k: SymbolKindConstant, + want: "Constant", + }, + { + name: "String", + k: SymbolKindString, + want: "String", + }, + { + name: "Number", + k: SymbolKindNumber, + want: "Number", + }, + { + name: "Boolean", + k: SymbolKindBoolean, + want: "Boolean", + }, + { + name: "Array", + k: SymbolKindArray, + want: "Array", + }, + { + name: "Object", + k: SymbolKindObject, + want: "Object", + }, + { + name: "Key", + k: SymbolKindKey, + want: "Key", + }, + { + name: "Null", + k: SymbolKindNull, + want: "Null", + }, + { + name: "EnumMember", + k: SymbolKindEnumMember, + want: "EnumMember", + }, + { + name: "Struct", + k: SymbolKindStruct, + want: "Struct", + }, + { + name: "Event", + k: SymbolKindEvent, + want: "Event", + }, + { + name: "Operator", + k: SymbolKindOperator, + want: "Operator", + }, + { + name: "TypeParameter", + k: SymbolKindTypeParameter, + want: "TypeParameter", + }, + { + name: "Unknown", + k: SymbolKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("SymbolKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestSymbolTag_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k SymbolTag + want string + }{ + { + name: "Deprecated", + k: SymbolTagDeprecated, + want: "Deprecated", + }, + { + name: "Unknown", + k: SymbolTag(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("SymbolTag.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestDocumentSymbol(t *testing.T) { + t.Parallel() + + const ( + want = `{"name":"test symbol","detail":"test detail","kind":1,"tags":[1],"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":6}},"selectionRange":{"start":{"line":25,"character":3},"end":{"line":26,"character":10}},"children":[{"name":"child symbol","detail":"child detail","kind":11,"deprecated":true,"range":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}},"selectionRange":{"start":{"line":255,"character":5},"end":{"line":255,"character":8}}}]}` + wantInvalid = `{"name":"invalid symbol","detail":"invalid detail","kind":1,"tags":[0],"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"selectionRange":{"start":{"line":2,"character":5},"end":{"line":3,"character":1}},"children":[{"name":"invalid child symbol","kind":1,"detail":"invalid child detail","range":{"start":{"line":255,"character":4},"end":{"line":255,"character":10}},"selectionRange":{"start":{"line":255,"character":5},"end":{"line":255,"character":8}}}]}` + ) + wantType := DocumentSymbol{ + Name: "test symbol", + Detail: "test detail", + Kind: SymbolKindFile, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Deprecated: false, + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 6, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 25, + Character: 3, + }, + End: Position{ + Line: 26, + Character: 10, + }, + }, + Children: []DocumentSymbol{ + { + Name: "child symbol", + Detail: "child detail", + Kind: SymbolKindInterface, + Deprecated: true, + Range: Range{ + Start: Position{ + Line: 255, + Character: 4, + }, + End: Position{ + Line: 255, + Character: 10, + }, + }, + SelectionRange: Range{ + Start: Position{ + Line: 255, + Character: 5, + }, + End: Position{ + Line: 255, + Character: 8, + }, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentSymbol + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentSymbol + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentSymbol + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestSymbolInformation(t *testing.T) { + t.Parallel() + + const ( + want = `{"name":"test symbol","kind":1,"tags":[1],"deprecated":true,"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"containerName":"testContainerName"}` + wantNilAll = `{"name":"test symbol","kind":1,"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}}` + wantInvalid = `{"name":"invalid symbol","kind":1,"tags":[0],"deprecated":false,"location":{"uri":"file:///path/to/test_test.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"containerName":"invalidContainerName"}` + ) + wantType := SymbolInformation{ + Name: "test symbol", + Kind: 1, + Tags: []SymbolTag{ + SymbolTagDeprecated, + }, + Deprecated: true, + Location: Location{ + URI: uri.File("/path/to/test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + ContainerName: "testContainerName", + } + wantTypeNilAll := SymbolInformation{ + Name: "test symbol", + Kind: 1, + Deprecated: false, + Location: Location{ + URI: uri.File("/path/to/test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field SymbolInformation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want SymbolInformation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got SymbolInformation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeActionParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"},"context":{"diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"only":["quickfix"]},"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":6}}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/test.go"},"context":{"diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"only":["quickfix"]},"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}}` + ) + wantType := CodeActionParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Context: CodeActionContext{ + Diagnostics: []Diagnostic{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "test.go", + }, + }, + }, + }, + Only: []CodeActionKind{ + QuickFix, + }, + }, + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 6, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeActionParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeActionParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeActionParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCodeActionKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k CodeActionKind + want string + }{ + { + name: "QuickFix", + k: QuickFix, + want: "quickfix", + }, + { + name: "Refactor", + k: Refactor, + want: "refactor", + }, + { + name: "RefactorExtract", + k: RefactorExtract, + want: "refactor.extract", + }, + { + name: "RefactorInline", + k: RefactorInline, + want: "refactor.inline", + }, + { + name: "RefactorRewrite", + k: RefactorRewrite, + want: "refactor.rewrite", + }, + { + name: "Source", + k: Source, + want: "source", + }, + { + name: "SourceOrganizeImports", + k: SourceOrganizeImports, + want: "source.organizeImports", + }, + { + name: "Unknown", + k: CodeActionKind(""), + want: "", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k; got != CodeActionKind(tt.want) { + t.Errorf("CodeActionKind = %v, want %v", tt.want, got) + } + }) + } +} + +func TestCodeActionContext(t *testing.T) { + t.Parallel() + + const ( + want = `{"diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"only":["quickfix"]}` + wantInvalid = `{"diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"only":["quickfix"]}` + ) + wantType := CodeActionContext{ + Diagnostics: []Diagnostic{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "test.go", + }, + }, + }, + }, + Only: []CodeActionKind{ + QuickFix, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeActionContext + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeActionContext + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeActionContext + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeAction(t *testing.T) { + t.Parallel() + + const ( + want = `{"title":"Refactoring","kind":"refactor.rewrite","diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"isPreferred":true,"disabled":{"reason":"testReason"},"edit":{"changes":{"file:///path/to/test.go":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/test.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}]},"command":{"title":"rewrite","command":"rewriter","arguments":["-w"]},"data":"testData"}` + wantInvalid = `{"title":"Refactoring","kind":"refactor","diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/test.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"test.go"}]}],"isPreferred":false,"disabled":{"reason":"invalidReason"},"edit":{"changes":{"file:///path/to/test.go":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/test.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}]},"command":{"title":"rewrite","command":"rewriter","arguments":["-w"]}}` + ) + wantType := CodeAction{ + Title: "Refactoring", + Kind: RefactorRewrite, + Diagnostics: []Diagnostic{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Severity: DiagnosticSeverityError, + Code: "foo/bar", + Source: "test foo bar", + Message: "foo bar", + RelatedInformation: []DiagnosticRelatedInformation{ + { + Location: Location{ + URI: uri.File("/path/to/test.go"), + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + }, + Message: "test.go", + }, + }, + }, + }, + IsPreferred: true, + Disabled: &CodeActionDisable{ + Reason: "testReason", + }, + Edit: &WorkspaceEdit{ + Changes: map[uri.URI][]TextEdit{ + uri.File("/path/to/test.go"): { + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + DocumentChanges: []TextDocumentEdit{ + { + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + }, + }, + Command: &Command{ + Title: "rewrite", + Command: "rewriter", + Arguments: []any{"-w"}, + }, + Data: "testData", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeAction + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeAction + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeAction + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeActionRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}],"codeActionKinds":["quickfix","refactor"]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}],"codeActionKinds":["quickfix","refactor"]}` + ) + wantType := CodeActionRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + CodeActionOptions: CodeActionOptions{ + CodeActionKinds: []CodeActionKind{ + QuickFix, + Refactor, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeActionRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeActionRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeActionRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeLensParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := CodeLensParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeLensParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeLensParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeLensParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestCodeLens(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"command":{"title":"rewrite","command":"rewriter","arguments":["-w"]},"data":"testData"}` + wantNilAll = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"command":{"title":"rewrite","command":"rewriter","arguments":["-w"]},"data":"invalidData"}` + ) + wantType := CodeLens{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Command: &Command{ + Title: "rewrite", + Command: "rewriter", + Arguments: []any{"-w"}, + }, + Data: "testData", + } + wantTypeNilAll := CodeLens{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeLens + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeLens + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeLens + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestCodeLensRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}],"resolveProvider":true}` + wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}],"resolveProvider":false}` + ) + wantType := CodeLensRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + ResolveProvider: true, + } + wantTypeNilAll := CodeLensRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field CodeLensRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want CodeLensRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got CodeLensRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentLinkParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"}}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := DocumentLinkParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentLinkParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentLinkParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentLinkParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDocumentLink(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"target":"file:///path/to/test.go","tooltip":"testTooltip","data":"testData"}` + wantNilAll = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"target":"file:///path/to/test.go","tooltip":"invalidTooltip","data":"testData"}` + ) + wantType := DocumentLink{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Target: uri.File("/path/to/test.go"), + Tooltip: "testTooltip", + Data: "testData", + } + wantTypeNilAll := DocumentLink{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentLink + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentLink + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentLink + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentColorParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := DocumentColorParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentColorParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentColorParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentColorParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestColorInformation(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"color":{"alpha":1,"blue":0.2,"green":0.3,"red":0.4}}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"color":{"alpha":0,"blue":0.4,"green":0.3,"red":0.2}}` + ) + wantType := ColorInformation{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Color: Color{ + Alpha: 1, + Blue: 0.2, + Green: 0.3, + Red: 0.4, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ColorInformation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ColorInformation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ColorInformation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestColor(t *testing.T) { + t.Parallel() + + const ( + want = `{"alpha":1,"blue":0.2,"green":0.3,"red":0.4}` + wantInvalid = `{"alpha":0,"blue":0.4,"green":0.3,"red":0.2}` + ) + wantType := Color{ + Alpha: 1, + Blue: 0.2, + Green: 0.3, + Red: 0.4, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Color + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Color + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Color + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestColorPresentationParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","textDocument":{"uri":"file:///path/to/test.go"},"color":{"alpha":1,"blue":0.2,"green":0.3,"red":0.4},"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/test.go"},"color":{"alpha":0,"blue":0.4,"green":0.3,"red":0.2},"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}}` + ) + wantType := ColorPresentationParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Color: Color{ + Alpha: 1, + Blue: 0.2, + Green: 0.3, + Red: 0.4, + }, + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ColorPresentationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ColorPresentationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ColorPresentationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestColorPresentation(t *testing.T) { + t.Parallel() + + const ( + want = `{"label":"testLabel","textEdit":{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"},"additionalTextEdits":[{"range":{"start":{"line":100,"character":10},"end":{"line":102,"character":15}},"newText":"baz qux"}]}` + wantNilAll = `{"label":"testLabel"}` + wantInvalid = `{"label":"invalidLabel","textEdit":{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"quux quuz"},"additionalTextEdits":[{"range":{"start":{"line":105,"character":15},"end":{"line":107,"character":20}},"newText":"corge grault"}]}` + ) + wantType := ColorPresentation{ + Label: "testLabel", + TextEdit: &TextEdit{ + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + AdditionalTextEdits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 100, + Character: 10, + }, + End: Position{ + Line: 102, + Character: 15, + }, + }, + NewText: "baz qux", + }, + }, + } + wantTypeNilAll := ColorPresentation{ + Label: "testLabel", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ColorPresentation + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ColorPresentation + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ColorPresentation + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentFormattingParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","options":{"insertSpaces":true,"tabSize":4},"textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"workDoneToken":"` + invalidWorkDoneToken + `","options":{"insertSpaces":false,"tabSize":2},"textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := DocumentFormattingParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + Options: FormattingOptions{ + InsertSpaces: true, + TabSize: 4, + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentFormattingParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentFormattingParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentFormattingParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestFormattingOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"insertSpaces":true,"tabSize":4,"trimTrailingWhitespace":true,"insertFinalNewline":true,"trimFinalNewlines":true,"key":{"test":"key"}}` + wantInvalid = `{"insertSpaces":false,"tabSize":2,"trimTrailingWhitespace":false,"insertFinalNewline":false,"trimFinalNewlines":false}` + ) + wantType := FormattingOptions{ + InsertSpaces: true, + TabSize: 4, + TrimTrailingWhitespace: true, + InsertFinalNewline: true, + TrimFinalNewlines: true, + Key: map[string]any{ + "test": "key", + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field FormattingOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want FormattingOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FormattingOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentRangeFormattingParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","textDocument":{"uri":"file:///path/to/test.go"},"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"options":{"insertSpaces":true,"tabSize":4}}` + wantInvalid = `{"workDoneToken":"` + invalidWorkDoneToken + `","textDocument":{"uri":"file:///path/to/invalid.go"},"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"options":{"insertSpaces":false,"tabSize":2}}` + ) + wantType := DocumentRangeFormattingParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + Options: FormattingOptions{ + InsertSpaces: true, + TabSize: 4, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentRangeFormattingParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentRangeFormattingParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentRangeFormattingParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestDocumentOnTypeFormattingParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1},"ch":"character","options":{"insertSpaces":true,"tabSize":4}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"position":{"line":2,"character":1},"ch":"invalidChar","options":{"insertSpaces":false,"tabSize":2}}` + ) + wantType := DocumentOnTypeFormattingParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + Ch: "character", + Options: FormattingOptions{ + InsertSpaces: true, + TabSize: 4, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentOnTypeFormattingParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentOnTypeFormattingParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentOnTypeFormattingParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDocumentOnTypeFormattingRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}],"firstTriggerCharacter":"}","moreTriggerCharacter":[".","{"]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}],"firstTriggerCharacter":"{","moreTriggerCharacter":[" ","("]}` + ) + wantType := DocumentOnTypeFormattingRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + FirstTriggerCharacter: "}", + MoreTriggerCharacter: []string{".", "{"}, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DocumentOnTypeFormattingRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DocumentOnTypeFormattingRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DocumentOnTypeFormattingRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRenameParams(t *testing.T) { + t.Parallel() + + const ( + wantPartialResultToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1},"partialResultToken":"` + wantPartialResultToken + `","newName":"newNameSymbol"}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"position":{"line":2,"character":1},"partialResultToken":"` + invalidPartialResultToken + `","newName":"invalidSymbol"}` + ) + wantType := RenameParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + NewName: "newNameSymbol", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field RenameParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want RenameParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestRenameRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}],"prepareProvider":true}` + wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}],"prepareProvider":false}` + ) + wantType := RenameRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + PrepareProvider: true, + } + wantTypeNilAll := RenameRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field RenameRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want RenameRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RenameRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestPrepareRenameParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"position":{"line":2,"character":0}}` + ) + wantType := PrepareRenameParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field PrepareRenameParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want PrepareRenameParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got PrepareRenameParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestFoldingRangeParams(t *testing.T) { + t.Parallel() + + const ( + wantPartialResultToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"position":{"line":25,"character":1},"partialResultToken":"` + wantPartialResultToken + `"}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"position":{"line":2,"character":0},"partialResultToken":"` + invalidPartialResultToken + `"}` + ) + wantType := FoldingRangeParams{ + TextDocumentPositionParams: TextDocumentPositionParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Position: Position{ + Line: 25, + Character: 1, + }, + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field FoldingRangeParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want FoldingRangeParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FoldingRangeParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestFoldingRangeKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + s FoldingRangeKind + want string + }{ + { + name: "Comment", + s: CommentFoldingRange, + want: "comment", + }, + { + name: "Imports", + s: ImportsFoldingRange, + want: "imports", + }, + { + name: "Region", + s: RegionFoldingRange, + want: "region", + }, + { + name: "Unknown", + s: FoldingRangeKind(""), + want: "", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.s; !strings.EqualFold(tt.want, string(got)) { + t.Errorf("FoldingRangeKind(%v), want %v", tt.want, got) + } + }) + } +} + +func TestFoldingRange(t *testing.T) { + t.Parallel() + + const ( + want = `{"startLine":10,"startCharacter":1,"endLine":10,"endCharacter":8,"kind":"imports"}` + wantNilAll = `{"startLine":10,"endLine":10}` + wantInvalid = `{"startLine":0,"startCharacter":1,"endLine":0,"endCharacter":8,"kind":"comment"}` + ) + wantType := FoldingRange{ + StartLine: 10, + StartCharacter: 1, + EndLine: 10, + EndCharacter: 8, + Kind: ImportsFoldingRange, + } + wantTypeNilAll := FoldingRange{ + StartLine: 10, + EndLine: 10, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field FoldingRange + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want FoldingRange + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FoldingRange + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/progress.go b/templ/lsp/protocol/progress.go new file mode 100644 index 0000000..d1a2e9f --- /dev/null +++ b/templ/lsp/protocol/progress.go @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// WorkDoneProgressKind kind of WorkDoneProgress. +// +// @since 3.15.0. +type WorkDoneProgressKind string + +// list of WorkDoneProgressKind. +const ( + // WorkDoneProgressKindBegin kind of WorkDoneProgressBegin. + WorkDoneProgressKindBegin WorkDoneProgressKind = "begin" + + // WorkDoneProgressKindReport kind of WorkDoneProgressReport. + WorkDoneProgressKindReport WorkDoneProgressKind = "report" + + // WorkDoneProgressKindEnd kind of WorkDoneProgressEnd. + WorkDoneProgressKindEnd WorkDoneProgressKind = "end" +) + +// WorkDoneProgressBegin is the to start progress reporting a "$/progress" notification. +// +// @since 3.15.0. +type WorkDoneProgressBegin struct { + // Kind is the kind of WorkDoneProgressBegin. + // + // It must be WorkDoneProgressKindBegin. + Kind WorkDoneProgressKind `json:"kind"` + + // Title mandatory title of the progress operation. Used to briefly inform about + // the kind of operation being performed. + // + // Examples: "Indexing" or "Linking dependencies". + Title string `json:"title"` + + // Cancellable controls if a cancel button should show to allow the user to cancel the + // long running operation. Clients that don't support cancellation are allowed + // to ignore the setting. + Cancellable bool `json:"cancellable,omitempty"` + + // Message is optional, more detailed associated progress message. Contains + // complementary information to the `title`. + // + // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + // If unset, the previous progress message (if any) is still valid. + Message string `json:"message,omitempty"` + + // Percentage is optional progress percentage to display (value 100 is considered 100%). + // If not provided infinite progress is assumed and clients are allowed + // to ignore the `percentage` value in subsequent in report notifications. + // + // The value should be steadily rising. Clients are free to ignore values + // that are not following this rule. + Percentage uint32 `json:"percentage,omitempty"` +} + +// WorkDoneProgressReport is the reporting progress is done. +// +// @since 3.15.0. +type WorkDoneProgressReport struct { + // Kind is the kind of WorkDoneProgressReport. + // + // It must be WorkDoneProgressKindReport. + Kind WorkDoneProgressKind `json:"kind"` + + // Cancellable controls enablement state of a cancel button. + // + // Clients that don't support cancellation or don't support controlling the button's + // enablement state are allowed to ignore the property. + Cancellable bool `json:"cancellable,omitempty"` + + // Message is optional, more detailed associated progress message. Contains + // complementary information to the `title`. + // + // Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + // If unset, the previous progress message (if any) is still valid. + Message string `json:"message,omitempty"` + + // Percentage is optional progress percentage to display (value 100 is considered 100%). + // If not provided infinite progress is assumed and clients are allowed + // to ignore the `percentage` value in subsequent in report notifications. + // + // The value should be steadily rising. Clients are free to ignore values + // that are not following this rule. + Percentage uint32 `json:"percentage,omitempty"` +} + +// WorkDoneProgressEnd is the signaling the end of a progress reporting is done. +// +// @since 3.15.0. +type WorkDoneProgressEnd struct { + // Kind is the kind of WorkDoneProgressEnd. + // + // It must be WorkDoneProgressKindEnd. + Kind WorkDoneProgressKind `json:"kind"` + + // Message is optional, a final message indicating to for example indicate the outcome + // of the operation. + Message string `json:"message,omitempty"` +} + +// WorkDoneProgressParams is a parameter property of report work done progress. +// +// @since 3.15.0. +type WorkDoneProgressParams struct { + // WorkDoneToken an optional token that a server can use to report work done progress. + WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"` +} + +// PartialResultParams is the parameter literal used to pass a partial result token. +// +// @since 3.15.0. +type PartialResultParams struct { + // PartialResultToken an optional token that a server can use to report partial results + // (for example, streaming) to the client. + PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` +} diff --git a/templ/lsp/protocol/progress_test.go b/templ/lsp/protocol/progress_test.go new file mode 100644 index 0000000..23b4f85 --- /dev/null +++ b/templ/lsp/protocol/progress_test.go @@ -0,0 +1,509 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" +) + +func TestWorkDoneProgressBegin(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"begin","title":"testTitle","cancellable":true,"message":"testMessage","percentage":30}` + wantNil = `{"kind":"begin","title":"testTitle"}` + wantInvalid = `{"kind":"invalid","title":"invalidTitle","cancellable":false,"message":"invalidMessage","percentage":0}` + ) + wantType := WorkDoneProgressBegin{ + Kind: WorkDoneProgressKindBegin, + Title: "testTitle", + Cancellable: true, + Message: "testMessage", + Percentage: uint32(30), + } + wantTypeNil := WorkDoneProgressBegin{ + Kind: WorkDoneProgressKindBegin, + Title: "testTitle", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressBegin + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressBegin + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressBegin + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkDoneProgressReport(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"report","cancellable":true,"message":"testMessage","percentage":30}` + wantNil = `{"kind":"report"}` + wantInvalid = `{"kind":"invalid","cancellable":false,"message":"invalidMessage","percentage":0}` + ) + wantType := WorkDoneProgressReport{ + Kind: WorkDoneProgressKindReport, + Cancellable: true, + Message: "testMessage", + Percentage: uint32(30), + } + wantTypeNil := WorkDoneProgressReport{ + Kind: WorkDoneProgressKindReport, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressReport + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressReport + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressReport + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkDoneProgressEnd(t *testing.T) { + t.Parallel() + + const ( + want = `{"kind":"end","message":"testMessage"}` + wantNil = `{"kind":"end"}` + wantInvalid = `{"kind":"invalid","message":"invalidMessage"}` + ) + wantType := WorkDoneProgressEnd{ + Kind: WorkDoneProgressKindEnd, + Message: "testMessage", + } + wantTypeNil := WorkDoneProgressEnd{ + Kind: WorkDoneProgressKindEnd, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressEnd + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressEnd + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Nil", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressEnd + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkDoneProgressParams(t *testing.T) { + t.Parallel() + + const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + const want = `{"workDoneToken":"` + wantWorkDoneToken + `"}` + + wantType := WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestPartialResultParams(t *testing.T) { + t.Parallel() + + const wantPartialResultParams = "156edea9-9d8d-422f-b7ee-81a84594afbb" + const want = `{"partialResultToken":"` + wantPartialResultParams + `"}` + + wantType := PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultParams), + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field PartialResultParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want PartialResultParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got PartialResultParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultParams); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} diff --git a/templ/lsp/protocol/protocol.go b/templ/lsp/protocol/protocol.go new file mode 100644 index 0000000..e8f7ccb --- /dev/null +++ b/templ/lsp/protocol/protocol.go @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "context" + "log/slog" + + "github.com/a-h/templ/lsp/jsonrpc2" +) + +// NewServer returns the context in which client is embedded, jsonrpc2.Conn, and the Client. +func NewServer(ctx context.Context, server Server, stream jsonrpc2.Stream, logger *slog.Logger) (context.Context, jsonrpc2.Conn, Client) { + conn := jsonrpc2.NewConn(stream) + cliint := ClientDispatcher(conn, logger.With(slog.String("name", "client"))) + ctx = WithClient(ctx, cliint) + + conn.Go(ctx, + Handlers( + ServerHandler(logger, server, jsonrpc2.MethodNotFoundHandler), + ), + ) + + return ctx, conn, cliint +} + +// NewClient returns the context in which Client is embedded, jsonrpc2.Conn, and the Server. +func NewClient(ctx context.Context, client Client, stream jsonrpc2.Stream, logger *slog.Logger) (context.Context, jsonrpc2.Conn, Server) { + ctx = WithClient(ctx, client) + + conn := jsonrpc2.NewConn(stream) + conn.Go(ctx, + Handlers( + ClientHandler(logger, client, jsonrpc2.MethodNotFoundHandler), + ), + ) + server := ServerDispatcher(conn, logger.With(slog.String("name", "server"))) + + return ctx, conn, server +} diff --git a/templ/lsp/protocol/registration.go b/templ/lsp/protocol/registration.go new file mode 100644 index 0000000..1cb7ab7 --- /dev/null +++ b/templ/lsp/protocol/registration.go @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// Registration general parameters to register for a capability. +type Registration struct { + // ID is the id used to register the request. The id can be used to deregister + // the request again. + ID string `json:"id"` + + // Method is the method / capability to register for. + Method string `json:"method"` + + // RegisterOptions options necessary for the registration. + RegisterOptions any `json:"registerOptions,omitempty"` +} + +// RegistrationParams params of Register Capability. +type RegistrationParams struct { + Registrations []Registration `json:"registrations"` +} + +// TextDocumentRegistrationOptions TextDocumentRegistration options. +type TextDocumentRegistrationOptions struct { + // DocumentSelector a document selector to identify the scope of the registration. If set to null + // the document selector provided on the client side will be used. + DocumentSelector DocumentSelector `json:"documentSelector"` +} + +// Unregistration general parameters to unregister a capability. +type Unregistration struct { + // ID is the id used to unregister the request or notification. Usually an id + // provided during the register request. + ID string `json:"id"` + + // Method is the method / capability to unregister for. + Method string `json:"method"` +} + +// UnregistrationParams params of Unregistration. +type UnregistrationParams struct { + Unregisterations []Unregistration `json:"unregisterations"` +} diff --git a/templ/lsp/protocol/registration_test.go b/templ/lsp/protocol/registration_test.go new file mode 100644 index 0000000..b55d31f --- /dev/null +++ b/templ/lsp/protocol/registration_test.go @@ -0,0 +1,579 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" +) + +func TestRegistration(t *testing.T) { + t.Parallel() + + const ( + want = `{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}` + wantInterfaces = `{"id":"1","method":"testMethod","registerOptions":["foo","bar"]}` + wantNil = `{"id":"1","method":"testMethod"}` + wantInvalid = `{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}` + ) + wantTypeStringInterface := Registration{ + ID: "1", + Method: "testMethod", + RegisterOptions: map[string]any{ + "foo": "bar", + }, + } + wantTypeStringString := Registration{ + ID: "1", + Method: "testMethod", + RegisterOptions: map[string]string{ + "foo": "bar", + }, + } + wantTypeInterfaces := Registration{ + ID: "1", + Method: "testMethod", + RegisterOptions: []any{ + "foo", + "bar", + }, + } + wantTypeNil := Registration{ + ID: "1", + Method: "testMethod", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Registration + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "ValidStringInterface", + field: wantTypeStringInterface, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidStringString", + field: wantTypeStringString, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidInterfaces", + field: wantTypeInterfaces, + want: wantInterfaces, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantTypeStringInterface, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Registration + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "ValidStringInterface", + field: want, + want: wantTypeStringInterface, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidInterfaces", + field: wantInterfaces, + want: wantTypeInterfaces, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantTypeStringInterface, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Registration + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestRegistrationParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"registrations":[{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}]}` + wantNil = `{"registrations":[{"id":"1","method":"testMethod"}]}` + wantInvalid = `{"registrations":[{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}]}` + ) + wantType := RegistrationParams{ + Registrations: []Registration{ + { + ID: "1", + Method: "testMethod", + RegisterOptions: map[string]any{ + "foo": "bar", + }, + }, + }, + } + wantTypeNil := RegistrationParams{ + Registrations: []Registration{ + { + ID: "1", + Method: "testMethod", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field RegistrationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNil, + want: wantNil, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want RegistrationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNil, + want: wantTypeNil, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got RegistrationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}]}` + ) + wantType := TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + { + Language: "cpp", + Scheme: "untitled", + Pattern: "*.{cpp,hpp}", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field TextDocumentRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want TextDocumentRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestUnregistration(t *testing.T) { + t.Parallel() + + const ( + want = `{"id":"1","method":"testMethod"}` + wantInvalid = `{"id":"2","method":"invalidMethod"}` + ) + wantType := Unregistration{ + ID: "1", + Method: "testMethod", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field Unregistration + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want Unregistration + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got Unregistration + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestUnregistrationParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"unregisterations":[{"id":"1","method":"testMethod"}]}` + wantInvalid = `{"unregisterations":[{"id":"2","method":"invalidMethod"}]}` + ) + wantType := UnregistrationParams{ + Unregisterations: []Unregistration{ + { + ID: "1", + Method: "testMethod", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field UnregistrationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want UnregistrationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got UnregistrationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/selectionrange.go b/templ/lsp/protocol/selectionrange.go new file mode 100644 index 0000000..a45b758 --- /dev/null +++ b/templ/lsp/protocol/selectionrange.go @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// SelectionRangeProviderOptions selection range provider options interface. +type SelectionRangeProviderOptions any + +// SelectionRange represents a selection range represents a part of a selection hierarchy. +// +// A selection range may have a parent selection range that contains it. +// +// @since 3.15.0. +type SelectionRange struct { + // Range is the Range of this selection range. + Range Range `json:"range"` + + // Parent is the parent selection range containing this range. Therefore `parent.range` must contain this Range. + Parent *SelectionRange `json:"parent,omitempty"` +} + +// EnableSelectionRange is the whether the selection range. +type EnableSelectionRange bool + +// compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface. +var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil) + +// Value implements SelectionRangeProviderOptions interface. +func (v EnableSelectionRange) Value() any { + return bool(v) +} + +// NewEnableSelectionRange returns the new EnableSelectionRange underlying types SelectionRangeProviderOptions. +func NewEnableSelectionRange(enable bool) SelectionRangeProviderOptions { + v := EnableSelectionRange(enable) + + return &v +} + +// SelectionRangeOptions is the server capability of selection range. +type SelectionRangeOptions struct { + WorkDoneProgressOptions +} + +// compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface. +var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil) + +// Value implements SelectionRangeProviderOptions interface. +func (v *SelectionRangeOptions) Value() any { + return v +} + +// NewSelectionRangeOptions returns the new SelectionRangeOptions underlying types SelectionRangeProviderOptions. +func NewSelectionRangeOptions(enableWorkDoneProgress bool) SelectionRangeProviderOptions { + v := SelectionRangeOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: enableWorkDoneProgress, + }, + } + + return &v +} + +// SelectionRangeRegistrationOptions is the server capability of selection range registration. +type SelectionRangeRegistrationOptions struct { + SelectionRangeOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +// compile time check whether the SelectionRangeRegistrationOptions implements a SelectionRangeProviderOptions interface. +var _ SelectionRangeProviderOptions = (*SelectionRangeRegistrationOptions)(nil) + +// Value implements SelectionRangeProviderOptions interface. +func (v *SelectionRangeRegistrationOptions) Value() any { + return v +} + +// NewSelectionRangeRegistrationOptions returns the new SelectionRangeRegistrationOptions underlying types SelectionRangeProviderOptions. +func NewSelectionRangeRegistrationOptions(enableWorkDoneProgress bool, selector DocumentSelector, id string) SelectionRangeProviderOptions { + v := SelectionRangeRegistrationOptions{ + SelectionRangeOptions: SelectionRangeOptions{ + WorkDoneProgressOptions: WorkDoneProgressOptions{ + WorkDoneProgress: enableWorkDoneProgress, + }, + }, + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: selector, + }, + StaticRegistrationOptions: StaticRegistrationOptions{ + ID: id, + }, + } + + return &v +} + +// SelectionRangeParams represents a parameter literal used in selection range requests. +// +// @since 3.15.0. +type SelectionRangeParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Positions is the positions inside the text document. + Positions []Position `json:"positions"` +} diff --git a/templ/lsp/protocol/semantic_token.go b/templ/lsp/protocol/semantic_token.go new file mode 100644 index 0000000..c2d1f3a --- /dev/null +++ b/templ/lsp/protocol/semantic_token.go @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: 2021 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// SemanticTokenTypes represents a type of semantic token. +// +// @since 3.16.0. +type SemanticTokenTypes string + +// list of SemanticTokenTypes. +const ( + SemanticTokenNamespace SemanticTokenTypes = "namespace" + + // Represents a generic type. Acts as a fallback for types which + // can't be mapped to a specific type like class or enum. + SemanticTokenType SemanticTokenTypes = "type" + SemanticTokenClass SemanticTokenTypes = "class" + SemanticTokenEnum SemanticTokenTypes = "enum" + SemanticTokenInterface SemanticTokenTypes = "interface" + SemanticTokenStruct SemanticTokenTypes = "struct" + SemanticTokenTypeParameter SemanticTokenTypes = "typeParameter" + SemanticTokenParameter SemanticTokenTypes = "parameter" + SemanticTokenVariable SemanticTokenTypes = "variable" + SemanticTokenProperty SemanticTokenTypes = "property" + SemanticTokenEnumMember SemanticTokenTypes = "enumMember" + SemanticTokenEvent SemanticTokenTypes = "event" + SemanticTokenFunction SemanticTokenTypes = "function" + SemanticTokenMethod SemanticTokenTypes = "method" + SemanticTokenMacro SemanticTokenTypes = "macro" + SemanticTokenKeyword SemanticTokenTypes = "keyword" + SemanticTokenModifier SemanticTokenTypes = "modifier" + SemanticTokenComment SemanticTokenTypes = "comment" + SemanticTokenString SemanticTokenTypes = "string" + SemanticTokenNumber SemanticTokenTypes = "number" + SemanticTokenRegexp SemanticTokenTypes = "regexp" + SemanticTokenOperator SemanticTokenTypes = "operator" +) + +// SemanticTokenModifiers represents a modifiers of semantic token. +// +// @since 3.16.0. +type SemanticTokenModifiers string + +// list of SemanticTokenModifiers. +const ( + SemanticTokenModifierDeclaration SemanticTokenModifiers = "declaration" + SemanticTokenModifierDefinition SemanticTokenModifiers = "definition" + SemanticTokenModifierReadonly SemanticTokenModifiers = "readonly" + SemanticTokenModifierStatic SemanticTokenModifiers = "static" + SemanticTokenModifierDeprecated SemanticTokenModifiers = "deprecated" + SemanticTokenModifierAbstract SemanticTokenModifiers = "abstract" + SemanticTokenModifierAsync SemanticTokenModifiers = "async" + SemanticTokenModifierModification SemanticTokenModifiers = "modification" + SemanticTokenModifierDocumentation SemanticTokenModifiers = "documentation" + SemanticTokenModifierDefaultLibrary SemanticTokenModifiers = "defaultLibrary" +) + +// TokenFormat is an additional token format capability to allow future extensions of the format. +// +// @since 3.16.0. +type TokenFormat string + +// TokenFormatRelative described using relative positions. +const TokenFormatRelative TokenFormat = "relative" + +// SemanticTokensLegend is the on the capability level types and modifiers are defined using strings. +// +// However the real encoding happens using numbers. +// +// The server therefore needs to let the client know which numbers it is using for which types and modifiers. +// +// @since 3.16.0. +type SemanticTokensLegend struct { + // TokenTypes is the token types a server uses. + TokenTypes []SemanticTokenTypes `json:"tokenTypes"` + + // TokenModifiers is the token modifiers a server uses. + TokenModifiers []SemanticTokenModifiers `json:"tokenModifiers"` +} + +// SemanticTokensParams params for the SemanticTokensFull request. +// +// @since 3.16.0. +type SemanticTokensParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// SemanticTokens is the result of SemanticTokensFull request. +// +// @since 3.16.0. +type SemanticTokens struct { + // ResultID an optional result id. If provided and clients support delta updating + // the client will include the result id in the next semantic token request. + // + // A server can then instead of computing all semantic tokens again simply + // send a delta. + ResultID string `json:"resultId,omitempty"` + + // Data is the actual tokens. + Data []uint32 `json:"data"` +} + +// SemanticTokensPartialResult is the partial result of SemanticTokensFull request. +// +// @since 3.16.0. +type SemanticTokensPartialResult struct { + // Data is the actual tokens. + Data []uint32 `json:"data"` +} + +// SemanticTokensDeltaParams params for the SemanticTokensFullDelta request. +// +// @since 3.16.0. +type SemanticTokensDeltaParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // PreviousResultID is the result id of a previous response. + // + // The result Id can either point to a full response or a delta response depending on what was received last. + PreviousResultID string `json:"previousResultId"` +} + +// SemanticTokensDelta result of SemanticTokensFullDelta request. +// +// @since 3.16.0. +type SemanticTokensDelta struct { + // ResultID is the result id. + // + // This field is readonly. + ResultID string `json:"resultId,omitempty"` + + // Edits is the semantic token edits to transform a previous result into a new + // result. + Edits []SemanticTokensEdit `json:"edits"` +} + +// SemanticTokensDeltaPartialResult is the partial result of SemanticTokensFullDelta request. +// +// @since 3.16.0. +type SemanticTokensDeltaPartialResult struct { + Edits []SemanticTokensEdit `json:"edits"` +} + +// SemanticTokensEdit is the semantic token edit. +// +// @since 3.16.0. +type SemanticTokensEdit struct { + // Start is the start offset of the edit. + Start uint32 `json:"start"` + + // DeleteCount is the count of elements to remove. + DeleteCount uint32 `json:"deleteCount"` + + // Data is the elements to insert. + Data []uint32 `json:"data,omitempty"` +} + +// SemanticTokensRangeParams params for the SemanticTokensRange request. +// +// @since 3.16.0. +type SemanticTokensRangeParams struct { + WorkDoneProgressParams + PartialResultParams + + // TextDocument is the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Range is the range the semantic tokens are requested for. + Range Range `json:"range"` +} diff --git a/templ/lsp/protocol/server.go b/templ/lsp/protocol/server.go new file mode 100644 index 0000000..0a5d06c --- /dev/null +++ b/templ/lsp/protocol/server.go @@ -0,0 +1,1893 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "bytes" + "context" + "fmt" + "log/slog" + + "encoding/json" + + "github.com/a-h/templ/lsp/jsonrpc2" + "github.com/a-h/templ/lsp/xcontext" +) + +// ServerDispatcher returns a Server that dispatches LSP requests across the +// given jsonrpc2 connection. +func ServerDispatcher(conn jsonrpc2.Conn, logger *slog.Logger) Server { + return &server{ + Conn: conn, + logger: logger, + } +} + +// ServerHandler jsonrpc2.Handler of Language Server Prococol Server. +// +//nolint:unparam +func ServerHandler(log *slog.Logger, server Server, handler jsonrpc2.Handler) jsonrpc2.Handler { + h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error { + if ctx.Err() != nil { + xctx := xcontext.Detach(ctx) + + return reply(xctx, nil, ErrRequestCancelled) + } + handled, err := serverDispatch(ctx, log, server, reply, req) + if handled || err != nil { + return err + } + + // TODO: This code is wrong, it ignores handler and assumes non standard + // request handles everything + // non standard request should just be a layered handler. + var params any + if err := json.Unmarshal(req.Params(), ¶ms); err != nil { + return replyParseError(ctx, reply, err) + } + + resp, err := server.Request(ctx, req.Method(), params) + + return reply(ctx, resp, err) + } + + return h +} + +// serverDispatch implements jsonrpc2.Handler. +// +//nolint:gocognit,funlen,gocyclo,cyclop +func serverDispatch(ctx context.Context, logger *slog.Logger, server Server, reply jsonrpc2.Replier, req jsonrpc2.Request) (handled bool, err error) { + if ctx.Err() != nil { + return true, reply(ctx, nil, ErrRequestCancelled) + } + + dec := json.NewDecoder(bytes.NewReader(req.Params())) + + switch req.Method() { + case MethodInitialize: // request + defer logger.Debug(MethodInitialize, slog.Any("error", err)) + + var params InitializeParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Initialize(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodInitialized: // notification + defer logger.Debug(MethodInitialized, slog.Any("error", err)) + + var params InitializedParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.Initialized(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodShutdown: // request + defer logger.Debug(MethodShutdown, slog.Any("error", err)) + + if len(req.Params()) > 0 { + return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + + err := server.Shutdown(ctx) + + return true, reply(ctx, nil, err) + + case MethodExit: // notification + defer logger.Debug(MethodExit, slog.Any("error", err)) + + if len(req.Params()) > 0 { + return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + + err := server.Exit(ctx) + + return true, reply(ctx, nil, err) + + case MethodWorkDoneProgressCancel: // notification + defer logger.Debug(MethodWorkDoneProgressCancel, slog.Any("error", err)) + + var params WorkDoneProgressCancelParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.WorkDoneProgressCancel(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodLogTrace: // notification + defer logger.Debug(MethodLogTrace, slog.Any("error", err)) + + var params LogTraceParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.LogTrace(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodSetTrace: // notification + defer logger.Debug(MethodSetTrace, slog.Any("error", err)) + + var params SetTraceParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.SetTrace(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentCodeAction: // request + defer logger.Debug(MethodTextDocumentCodeAction, slog.Any("error", err)) + + var params CodeActionParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.CodeAction(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentCodeLens: // request + defer logger.Debug(MethodTextDocumentCodeLens, slog.Any("error", err)) + + var params CodeLensParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.CodeLens(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodCodeLensResolve: // request + defer logger.Debug(MethodCodeLensResolve, slog.Any("error", err)) + + var params CodeLens + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.CodeLensResolve(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentColorPresentation: // request + defer logger.Debug(MethodTextDocumentColorPresentation, slog.Any("error", err)) + + var params ColorPresentationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.ColorPresentation(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentCompletion: // request + defer logger.Debug(MethodTextDocumentCompletion, slog.Any("error", err)) + + var params CompletionParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Completion(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodCompletionItemResolve: // request + defer logger.Debug(MethodCompletionItemResolve, slog.Any("error", err)) + + var params CompletionItem + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.CompletionResolve(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDeclaration: // request + defer logger.Debug(MethodTextDocumentDeclaration, slog.Any("error", err)) + + var params DeclarationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Declaration(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDefinition: // request + defer logger.Debug(MethodTextDocumentDefinition, slog.Any("error", err)) + + var params DefinitionParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Definition(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDidChange: // notification + defer logger.Debug(MethodTextDocumentDidChange, slog.Any("error", err)) + + var params DidChangeTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidChange(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWorkspaceDidChangeConfiguration: // notification + defer logger.Debug(MethodWorkspaceDidChangeConfiguration, slog.Any("error", err)) + + var params DidChangeConfigurationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidChangeConfiguration(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWorkspaceDidChangeWatchedFiles: // notification + defer logger.Debug(MethodWorkspaceDidChangeWatchedFiles, slog.Any("error", err)) + + var params DidChangeWatchedFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidChangeWatchedFiles(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWorkspaceDidChangeWorkspaceFolders: // notification + defer logger.Debug(MethodWorkspaceDidChangeWorkspaceFolders, slog.Any("error", err)) + + var params DidChangeWorkspaceFoldersParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidChangeWorkspaceFolders(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentDidClose: // notification + defer logger.Debug(MethodTextDocumentDidClose, slog.Any("error", err)) + + var params DidCloseTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidClose(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentDidOpen: // notification + defer logger.Debug(MethodTextDocumentDidOpen, slog.Any("error", err)) + + var params DidOpenTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidOpen(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentDidSave: // notification + defer logger.Debug(MethodTextDocumentDidSave, slog.Any("error", err)) + + var params DidSaveTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidSave(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentDocumentColor: // request + defer logger.Debug(MethodTextDocumentDocumentColor, slog.Any("error", err)) + + var params DocumentColorParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.DocumentColor(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDocumentHighlight: // request + defer logger.Debug(MethodTextDocumentDocumentHighlight, slog.Any("error", err)) + + var params DocumentHighlightParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.DocumentHighlight(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDocumentLink: // request + defer logger.Debug(MethodTextDocumentDocumentLink, slog.Any("error", err)) + + var params DocumentLinkParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.DocumentLink(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodDocumentLinkResolve: // request + defer logger.Debug(MethodDocumentLinkResolve, slog.Any("error", err)) + + var params DocumentLink + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.DocumentLinkResolve(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentDocumentSymbol: // request + defer logger.Debug(MethodTextDocumentDocumentSymbol, slog.Any("error", err)) + + var params DocumentSymbolParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.DocumentSymbol(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodWorkspaceExecuteCommand: // request + defer logger.Debug(MethodWorkspaceExecuteCommand, slog.Any("error", err)) + + var params ExecuteCommandParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.ExecuteCommand(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentFoldingRange: // request + defer logger.Debug(MethodTextDocumentFoldingRange, slog.Any("error", err)) + + var params FoldingRangeParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.FoldingRanges(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentFormatting: // request + defer logger.Debug(MethodTextDocumentFormatting, slog.Any("error", err)) + + var params DocumentFormattingParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Formatting(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentHover: // request + defer logger.Debug(MethodTextDocumentHover, slog.Any("error", err)) + + var params HoverParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Hover(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentImplementation: // request + defer logger.Debug(MethodTextDocumentImplementation, slog.Any("error", err)) + + var params ImplementationParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Implementation(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentOnTypeFormatting: // request + defer logger.Debug(MethodTextDocumentOnTypeFormatting, slog.Any("error", err)) + + var params DocumentOnTypeFormattingParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.OnTypeFormatting(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentPrepareRename: // request + defer logger.Debug(MethodTextDocumentPrepareRename, slog.Any("error", err)) + + var params PrepareRenameParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.PrepareRename(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentRangeFormatting: // request + defer logger.Debug(MethodTextDocumentRangeFormatting, slog.Any("error", err)) + + var params DocumentRangeFormattingParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.RangeFormatting(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentReferences: // request + defer logger.Debug(MethodTextDocumentReferences, slog.Any("error", err)) + + var params ReferenceParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.References(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentRename: // request + defer logger.Debug(MethodTextDocumentRename, slog.Any("error", err)) + + var params RenameParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Rename(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentSignatureHelp: // request + defer logger.Debug(MethodTextDocumentSignatureHelp, slog.Any("error", err)) + + var params SignatureHelpParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.SignatureHelp(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodWorkspaceSymbol: // request + defer logger.Debug(MethodWorkspaceSymbol, slog.Any("error", err)) + + var params WorkspaceSymbolParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Symbols(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentTypeDefinition: // request + defer logger.Debug(MethodTextDocumentTypeDefinition, slog.Any("error", err)) + + var params TypeDefinitionParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.TypeDefinition(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodTextDocumentWillSave: // notification + defer logger.Debug(MethodTextDocumentWillSave, slog.Any("error", err)) + + var params WillSaveTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.WillSave(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentWillSaveWaitUntil: // request + defer logger.Debug(MethodTextDocumentWillSaveWaitUntil, slog.Any("error", err)) + + var params WillSaveTextDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.WillSaveWaitUntil(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodShowDocument: // request + defer logger.Debug(MethodShowDocument, slog.Any("error", err)) + + var params ShowDocumentParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.ShowDocument(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodWillCreateFiles: // request + defer logger.Debug(MethodWillCreateFiles, slog.Any("error", err)) + + var params CreateFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.WillCreateFiles(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodDidCreateFiles: // notification + defer logger.Debug(MethodDidCreateFiles, slog.Any("error", err)) + + var params CreateFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidCreateFiles(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWillRenameFiles: // request + defer logger.Debug(MethodWillRenameFiles, slog.Any("error", err)) + + var params RenameFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.WillRenameFiles(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodDidRenameFiles: // notification + defer logger.Debug(MethodDidRenameFiles, slog.Any("error", err)) + + var params RenameFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidRenameFiles(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodWillDeleteFiles: // request + defer logger.Debug(MethodWillDeleteFiles, slog.Any("error", err)) + + var params DeleteFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.WillDeleteFiles(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodDidDeleteFiles: // notification + defer logger.Debug(MethodDidDeleteFiles, slog.Any("error", err)) + + var params DeleteFilesParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + err := server.DidDeleteFiles(ctx, ¶ms) + + return true, reply(ctx, nil, err) + + case MethodCodeLensRefresh: // request + defer logger.Debug(MethodCodeLensRefresh, slog.Any("error", err)) + + if len(req.Params()) > 0 { + return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + + err := server.CodeLensRefresh(ctx) + + return true, reply(ctx, nil, err) + + case MethodTextDocumentPrepareCallHierarchy: // request + defer logger.Debug(MethodTextDocumentPrepareCallHierarchy, slog.Any("error", err)) + + var params CallHierarchyPrepareParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.PrepareCallHierarchy(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodCallHierarchyIncomingCalls: // request + defer logger.Debug(MethodCallHierarchyIncomingCalls, slog.Any("error", err)) + + var params CallHierarchyIncomingCallsParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.IncomingCalls(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodCallHierarchyOutgoingCalls: // request + defer logger.Debug(MethodCallHierarchyOutgoingCalls, slog.Any("error", err)) + + var params CallHierarchyOutgoingCallsParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.OutgoingCalls(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodSemanticTokensFull: // request + defer logger.Debug(MethodSemanticTokensFull, slog.Any("error", err)) + + var params SemanticTokensParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.SemanticTokensFull(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodSemanticTokensFullDelta: // request + defer logger.Debug(MethodSemanticTokensFullDelta, slog.Any("error", err)) + + var params SemanticTokensDeltaParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.SemanticTokensFullDelta(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodSemanticTokensRange: // request + defer logger.Debug(MethodSemanticTokensRange, slog.Any("error", err)) + + var params SemanticTokensRangeParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.SemanticTokensRange(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodSemanticTokensRefresh: // request + defer logger.Debug(MethodSemanticTokensRefresh, slog.Any("error", err)) + + if len(req.Params()) > 0 { + return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams)) + } + + err := server.SemanticTokensRefresh(ctx) + + return true, reply(ctx, nil, err) + + case MethodLinkedEditingRange: // request + defer logger.Debug(MethodLinkedEditingRange, slog.Any("error", err)) + + var params LinkedEditingRangeParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.LinkedEditingRange(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + case MethodMoniker: // request + defer logger.Debug(MethodMoniker, slog.Any("error", err)) + + var params MonikerParams + if err := dec.Decode(¶ms); err != nil { + return true, replyParseError(ctx, reply, err) + } + + resp, err := server.Moniker(ctx, ¶ms) + + return true, reply(ctx, resp, err) + + default: + return false, nil + } +} + +// Server represents a Language Server Protocol server. +type Server interface { + Initialize(ctx context.Context, params *InitializeParams) (result *InitializeResult, err error) + Initialized(ctx context.Context, params *InitializedParams) (err error) + Shutdown(ctx context.Context) (err error) + Exit(ctx context.Context) (err error) + WorkDoneProgressCancel(ctx context.Context, params *WorkDoneProgressCancelParams) (err error) + LogTrace(ctx context.Context, params *LogTraceParams) (err error) + SetTrace(ctx context.Context, params *SetTraceParams) (err error) + CodeAction(ctx context.Context, params *CodeActionParams) (result []CodeAction, err error) + CodeLens(ctx context.Context, params *CodeLensParams) (result []CodeLens, err error) + CodeLensResolve(ctx context.Context, params *CodeLens) (result *CodeLens, err error) + ColorPresentation(ctx context.Context, params *ColorPresentationParams) (result []ColorPresentation, err error) + Completion(ctx context.Context, params *CompletionParams) (result *CompletionList, err error) + CompletionResolve(ctx context.Context, params *CompletionItem) (result *CompletionItem, err error) + Declaration(ctx context.Context, params *DeclarationParams) (result []Location /* Declaration | DeclarationLink[] | null */, err error) + Definition(ctx context.Context, params *DefinitionParams) (result []Location /* Definition | DefinitionLink[] | null */, err error) + DidChange(ctx context.Context, params *DidChangeTextDocumentParams) (err error) + DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) (err error) + DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) (err error) + DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) (err error) + DidClose(ctx context.Context, params *DidCloseTextDocumentParams) (err error) + DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) (err error) + DidSave(ctx context.Context, params *DidSaveTextDocumentParams) (err error) + DocumentColor(ctx context.Context, params *DocumentColorParams) (result []ColorInformation, err error) + DocumentHighlight(ctx context.Context, params *DocumentHighlightParams) (result []DocumentHighlight, err error) + DocumentLink(ctx context.Context, params *DocumentLinkParams) (result []DocumentLink, err error) + DocumentLinkResolve(ctx context.Context, params *DocumentLink) (result *DocumentLink, err error) + DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) (result []SymbolInformationOrDocumentSymbol, err error) + ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (result any, err error) + FoldingRanges(ctx context.Context, params *FoldingRangeParams) (result []FoldingRange, err error) + Formatting(ctx context.Context, params *DocumentFormattingParams) (result []TextEdit, err error) + Hover(ctx context.Context, params *HoverParams) (result *Hover, err error) + Implementation(ctx context.Context, params *ImplementationParams) (result []Location, err error) + OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) (result []TextEdit, err error) + PrepareRename(ctx context.Context, params *PrepareRenameParams) (result *Range, err error) + RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) (result []TextEdit, err error) + References(ctx context.Context, params *ReferenceParams) (result []Location, err error) + Rename(ctx context.Context, params *RenameParams) (result *WorkspaceEdit, err error) + SignatureHelp(ctx context.Context, params *SignatureHelpParams) (result *SignatureHelp, err error) + Symbols(ctx context.Context, params *WorkspaceSymbolParams) (result []SymbolInformation, err error) + TypeDefinition(ctx context.Context, params *TypeDefinitionParams) (result []Location, err error) + WillSave(ctx context.Context, params *WillSaveTextDocumentParams) (err error) + WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) (result []TextEdit, err error) + ShowDocument(ctx context.Context, params *ShowDocumentParams) (result *ShowDocumentResult, err error) + WillCreateFiles(ctx context.Context, params *CreateFilesParams) (result *WorkspaceEdit, err error) + DidCreateFiles(ctx context.Context, params *CreateFilesParams) (err error) + WillRenameFiles(ctx context.Context, params *RenameFilesParams) (result *WorkspaceEdit, err error) + DidRenameFiles(ctx context.Context, params *RenameFilesParams) (err error) + WillDeleteFiles(ctx context.Context, params *DeleteFilesParams) (result *WorkspaceEdit, err error) + DidDeleteFiles(ctx context.Context, params *DeleteFilesParams) (err error) + CodeLensRefresh(ctx context.Context) (err error) + PrepareCallHierarchy(ctx context.Context, params *CallHierarchyPrepareParams) (result []CallHierarchyItem, err error) + IncomingCalls(ctx context.Context, params *CallHierarchyIncomingCallsParams) (result []CallHierarchyIncomingCall, err error) + OutgoingCalls(ctx context.Context, params *CallHierarchyOutgoingCallsParams) (result []CallHierarchyOutgoingCall, err error) + SemanticTokensFull(ctx context.Context, params *SemanticTokensParams) (result *SemanticTokens, err error) + SemanticTokensFullDelta(ctx context.Context, params *SemanticTokensDeltaParams) (result any /* SemanticTokens | SemanticTokensDelta */, err error) + SemanticTokensRange(ctx context.Context, params *SemanticTokensRangeParams) (result *SemanticTokens, err error) + SemanticTokensRefresh(ctx context.Context) (err error) + LinkedEditingRange(ctx context.Context, params *LinkedEditingRangeParams) (result *LinkedEditingRanges, err error) + Moniker(ctx context.Context, params *MonikerParams) (result []Moniker, err error) + Request(ctx context.Context, method string, params any) (result any, err error) +} + +// list of server methods. +const ( + // MethodCancelRequest method name of "$/cancelRequest". + MethodCancelRequest = "$/cancelRequest" + + // MethodInitialize method name of "initialize". + MethodInitialize = "initialize" + + // MethodInitialized method name of "initialized". + MethodInitialized = "initialized" + + // MethodShutdown method name of "shutdown". + MethodShutdown = "shutdown" + + // MethodExit method name of "exit". + MethodExit = "exit" + + // MethodWorkDoneProgressCancel method name of "window/workDoneProgress/cancel". + MethodWorkDoneProgressCancel = "window/workDoneProgress/cancel" + + // MethodLogTrace method name of "$/logTrace". + MethodLogTrace = "$/logTrace" + + // MethodSetTrace method name of "$/setTrace". + MethodSetTrace = "$/setTrace" + + // MethodTextDocumentCodeAction method name of "textDocument/codeAction". + MethodTextDocumentCodeAction = "textDocument/codeAction" + + // MethodTextDocumentCodeLens method name of "textDocument/codeLens". + MethodTextDocumentCodeLens = "textDocument/codeLens" + + // MethodCodeLensResolve method name of "codeLens/resolve". + MethodCodeLensResolve = "codeLens/resolve" + + // MethodTextDocumentColorPresentation method name of "textDocument/colorPresentation". + MethodTextDocumentColorPresentation = "textDocument/colorPresentation" + + // MethodTextDocumentCompletion method name of "textDocument/completion". + MethodTextDocumentCompletion = "textDocument/completion" + + // MethodCompletionItemResolve method name of "completionItem/resolve". + MethodCompletionItemResolve = "completionItem/resolve" + + // MethodTextDocumentDeclaration method name of "textDocument/declaration". + MethodTextDocumentDeclaration = "textDocument/declaration" + + // MethodTextDocumentDefinition method name of "textDocument/definition". + MethodTextDocumentDefinition = "textDocument/definition" + + // MethodTextDocumentDidChange method name of "textDocument/didChange". + MethodTextDocumentDidChange = "textDocument/didChange" + + // MethodWorkspaceDidChangeConfiguration method name of "workspace/didChangeConfiguration". + MethodWorkspaceDidChangeConfiguration = "workspace/didChangeConfiguration" + + // MethodWorkspaceDidChangeWatchedFiles method name of "workspace/didChangeWatchedFiles". + MethodWorkspaceDidChangeWatchedFiles = "workspace/didChangeWatchedFiles" + + // MethodWorkspaceDidChangeWorkspaceFolders method name of "workspace/didChangeWorkspaceFolders". + MethodWorkspaceDidChangeWorkspaceFolders = "workspace/didChangeWorkspaceFolders" + + // MethodTextDocumentDidClose method name of "textDocument/didClose". + MethodTextDocumentDidClose = "textDocument/didClose" + + // MethodTextDocumentDidOpen method name of "textDocument/didOpen". + MethodTextDocumentDidOpen = "textDocument/didOpen" + + // MethodTextDocumentDidSave method name of "textDocument/didSave". + MethodTextDocumentDidSave = "textDocument/didSave" + + // MethodTextDocumentDocumentColor method name of"textDocument/documentColor". + MethodTextDocumentDocumentColor = "textDocument/documentColor" + + // MethodTextDocumentDocumentHighlight method name of "textDocument/documentHighlight". + MethodTextDocumentDocumentHighlight = "textDocument/documentHighlight" + + // MethodTextDocumentDocumentLink method name of "textDocument/documentLink". + MethodTextDocumentDocumentLink = "textDocument/documentLink" + + // MethodDocumentLinkResolve method name of "documentLink/resolve". + MethodDocumentLinkResolve = "documentLink/resolve" + + // MethodTextDocumentDocumentSymbol method name of "textDocument/documentSymbol". + MethodTextDocumentDocumentSymbol = "textDocument/documentSymbol" + + // MethodWorkspaceExecuteCommand method name of "workspace/executeCommand". + MethodWorkspaceExecuteCommand = "workspace/executeCommand" + + // MethodTextDocumentFoldingRange method name of "textDocument/foldingRange". + MethodTextDocumentFoldingRange = "textDocument/foldingRange" + + // MethodTextDocumentFormatting method name of "textDocument/formatting". + MethodTextDocumentFormatting = "textDocument/formatting" + + // MethodTextDocumentHover method name of "textDocument/hover". + MethodTextDocumentHover = "textDocument/hover" + + // MethodTextDocumentImplementation method name of "textDocument/implementation". + MethodTextDocumentImplementation = "textDocument/implementation" + + // MethodTextDocumentOnTypeFormatting method name of "textDocument/onTypeFormatting". + MethodTextDocumentOnTypeFormatting = "textDocument/onTypeFormatting" + + // MethodTextDocumentPrepareRename method name of "textDocument/prepareRename". + MethodTextDocumentPrepareRename = "textDocument/prepareRename" + + // MethodTextDocumentRangeFormatting method name of "textDocument/rangeFormatting". + MethodTextDocumentRangeFormatting = "textDocument/rangeFormatting" + + // MethodTextDocumentReferences method name of "textDocument/references". + MethodTextDocumentReferences = "textDocument/references" + + // MethodTextDocumentRename method name of "textDocument/rename". + MethodTextDocumentRename = "textDocument/rename" + + // MethodTextDocumentSignatureHelp method name of "textDocument/signatureHelp". + MethodTextDocumentSignatureHelp = "textDocument/signatureHelp" + + // MethodWorkspaceSymbol method name of "workspace/symbol". + MethodWorkspaceSymbol = "workspace/symbol" + + // MethodTextDocumentTypeDefinition method name of "textDocument/typeDefinition". + MethodTextDocumentTypeDefinition = "textDocument/typeDefinition" + + // MethodTextDocumentWillSave method name of "textDocument/willSave". + MethodTextDocumentWillSave = "textDocument/willSave" + + // MethodTextDocumentWillSaveWaitUntil method name of "textDocument/willSaveWaitUntil". + MethodTextDocumentWillSaveWaitUntil = "textDocument/willSaveWaitUntil" + + // MethodShowDocument method name of "window/showDocument". + MethodShowDocument = "window/showDocument" + + // MethodWillCreateFiles method name of "workspace/willCreateFiles". + MethodWillCreateFiles = "workspace/willCreateFiles" + + // MethodDidCreateFiles method name of "workspace/didCreateFiles". + MethodDidCreateFiles = "workspace/didCreateFiles" + + // MethodWillRenameFiles method name of "workspace/willRenameFiles". + MethodWillRenameFiles = "workspace/willRenameFiles" + + // MethodDidRenameFiles method name of "workspace/didRenameFiles". + MethodDidRenameFiles = "workspace/didRenameFiles" + + // MethodWillDeleteFiles method name of "workspace/willDeleteFiles". + MethodWillDeleteFiles = "workspace/willDeleteFiles" + + // MethodDidDeleteFiles method name of "workspace/didDeleteFiles". + MethodDidDeleteFiles = "workspace/didDeleteFiles" + + // MethodCodeLensRefresh method name of "workspace/codeLens/refresh". + MethodCodeLensRefresh = "workspace/codeLens/refresh" + + // MethodTextDocumentPrepareCallHierarchy method name of "textDocument/prepareCallHierarchy". + MethodTextDocumentPrepareCallHierarchy = "textDocument/prepareCallHierarchy" + + // MethodCallHierarchyIncomingCalls method name of "callHierarchy/incomingCalls". + MethodCallHierarchyIncomingCalls = "callHierarchy/incomingCalls" + + // MethodCallHierarchyOutgoingCalls method name of "callHierarchy/outgoingCalls". + MethodCallHierarchyOutgoingCalls = "callHierarchy/outgoingCalls" + + // MethodSemanticTokensFull method name of "textDocument/semanticTokens/full". + MethodSemanticTokensFull = "textDocument/semanticTokens/full" + + // MethodSemanticTokensFullDelta method name of "textDocument/semanticTokens/full/delta". + MethodSemanticTokensFullDelta = "textDocument/semanticTokens/full/delta" + + // MethodSemanticTokensRange method name of "textDocument/semanticTokens/range". + MethodSemanticTokensRange = "textDocument/semanticTokens/range" + + // MethodSemanticTokensRefresh method name of "workspace/semanticTokens/refresh". + MethodSemanticTokensRefresh = "workspace/semanticTokens/refresh" + + // MethodLinkedEditingRange method name of "textDocument/linkedEditingRange". + MethodLinkedEditingRange = "textDocument/linkedEditingRange" + + // MethodMoniker method name of "textDocument/moniker". + MethodMoniker = "textDocument/moniker" +) + +// server implements a Language Server Protocol server. +type server struct { + jsonrpc2.Conn + + logger *slog.Logger +} + +var _ Server = (*server)(nil) + +// Initialize sents the request as the first request from the client to the server. +// +// If the server receives a request or notification before the initialize request it should act as follows: +// +// - For a request the response should be an error with code: -32002. The message can be picked by the server. +// - Notifications should be dropped, except for the exit notification. This will allow the exit of a server without an initialize request. +// +// Until the server has responded to the initialize request with an InitializeResult, the client +// must not send any additional requests or notifications to the server. +// In addition the server is not allowed to send any requests or notifications to the client until +// it has responded with an InitializeResult, with the exception that during the initialize request +// the server is allowed to send the notifications window/showMessage, window/logMessage and telemetry/event +// as well as the window/showMessageRequest request to the client. +func (s *server) Initialize(ctx context.Context, params *InitializeParams) (_ *InitializeResult, err error) { + s.logger.Debug("call " + MethodInitialize) + defer s.logger.Debug("end "+MethodInitialize, slog.Any("error", err)) + + var result *InitializeResult + if err := Call(ctx, s.Conn, MethodInitialize, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Initialized sends the notification from the client to the server after the client received the result of the +// initialize request but before the client is sending any other request or notification to the server. +// +// The server can use the initialized notification for example to dynamically register capabilities. +// The initialized notification may only be sent once. +func (s *server) Initialized(ctx context.Context, params *InitializedParams) (err error) { + s.logger.Debug("notify " + MethodInitialized) + defer s.logger.Debug("end "+MethodInitialized, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodInitialized, params) +} + +// Shutdown sents the request from the client to the server. +// +// It asks the server to shut down, but to not exit (otherwise the response might not be delivered correctly to the client). +// There is a separate exit notification that asks the server to exit. +// +// Clients must not sent any notifications other than `exit` or requests to a server to which they have sent a shutdown requests. +// If a server receives requests after a shutdown request those requests should be errored with `InvalidRequest`. +func (s *server) Shutdown(ctx context.Context) (err error) { + s.logger.Debug("call " + MethodShutdown) + defer s.logger.Debug("end "+MethodShutdown, slog.Any("error", err)) + + return Call(ctx, s.Conn, MethodShutdown, nil, nil) +} + +// Exit a notification to ask the server to exit its process. +// +// The server should exit with success code 0 if the shutdown request has been received before; otherwise with error code 1. +func (s *server) Exit(ctx context.Context) (err error) { + s.logger.Debug("notify " + MethodExit) + defer s.logger.Debug("end "+MethodExit, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodExit, nil) +} + +// LogTrace a notification to log the trace of the server’s execution. +// +// The amount and content of these notifications depends on the current trace configuration. +// +// If trace is "off", the server should not send any logTrace notification. If trace is "message", +// the server should not add the "verbose" field in the LogTraceParams. +// +// @since 3.16.0. +func (s *server) LogTrace(ctx context.Context, params *LogTraceParams) (err error) { + s.logger.Debug("notify " + MethodLogTrace) + defer s.logger.Debug("end "+MethodLogTrace, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodLogTrace, params) +} + +// SetTrace a notification that should be used by the client to modify the trace setting of the server. +// +// @since 3.16.0. +func (s *server) SetTrace(ctx context.Context, params *SetTraceParams) (err error) { + s.logger.Debug("notify " + MethodSetTrace) + defer s.logger.Debug("end "+MethodSetTrace, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodSetTrace, params) +} + +// WorkDoneProgressCancel is the sends notification from the client to the server to cancel a progress initiated on the +// server side using the "window/workDoneProgress/create". +func (s *server) WorkDoneProgressCancel(ctx context.Context, params *WorkDoneProgressCancelParams) (err error) { + s.logger.Debug("call " + MethodWorkDoneProgressCancel) + defer s.logger.Debug("end "+MethodWorkDoneProgressCancel, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodWorkDoneProgressCancel, params) +} + +// CodeAction sends the request is from the client to the server to compute commands for a given text document and range. +// +// These commands are typically code fixes to either fix problems or to beautify/refactor code. The result of a `textDocument/codeAction` +// request is an array of `Command` literals which are typically presented in the user interface. +// +// To ensure that a server is useful in many clients the commands specified in a code actions should be handled by the +// server and not by the client (see `workspace/executeCommand` and `ServerCapabilities.executeCommandProvider`). +// If the client supports providing edits with a code action then the mode should be used. +func (s *server) CodeAction(ctx context.Context, params *CodeActionParams) (result []CodeAction, err error) { + s.logger.Debug("call " + MethodTextDocumentCodeAction) + defer s.logger.Debug("end "+MethodTextDocumentCodeAction, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentCodeAction, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// CodeLens sends the request from the client to the server to compute code lenses for a given text document. +func (s *server) CodeLens(ctx context.Context, params *CodeLensParams) (result []CodeLens, err error) { + s.logger.Debug("call " + MethodTextDocumentCodeLens) + defer s.logger.Debug("end "+MethodTextDocumentCodeLens, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentCodeLens, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// CodeLensResolve sends the request from the client to the server to resolve the command for a given code lens item. +func (s *server) CodeLensResolve(ctx context.Context, params *CodeLens) (_ *CodeLens, err error) { + s.logger.Debug("call " + MethodCodeLensResolve) + defer s.logger.Debug("end "+MethodCodeLensResolve, slog.Any("error", err)) + + var result *CodeLens + if err := Call(ctx, s.Conn, MethodCodeLensResolve, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// ColorPresentation sends the request from the client to the server to obtain a list of presentations for a color value at a given location. +// +// # Clients can use the result to +// +// - modify a color reference. +// - show in a color picker and let users pick one of the presentations. +func (s *server) ColorPresentation(ctx context.Context, params *ColorPresentationParams) (result []ColorPresentation, err error) { + s.logger.Debug("call " + MethodTextDocumentColorPresentation) + defer s.logger.Debug("end "+MethodTextDocumentColorPresentation, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentColorPresentation, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Completion sends the request from the client to the server to compute completion items at a given cursor position. +// +// Completion items are presented in the IntelliSense user interface. +// If computing full completion items is expensive, servers can additionally provide a handler for the completion item resolve request (‘completionItem/resolve’). +// +// This request is sent when a completion item is selected in the user interface. +// A typical use case is for example: the ‘textDocument/completion’ request doesn’t fill in the documentation property +// for returned completion items since it is expensive to compute. When the item is selected in the user interface then +// a ‘completionItem/resolve’ request is sent with the selected completion item as a parameter. +// +// The returned completion item should have the documentation property filled in. The request can delay the computation of +// the `detail` and `documentation` properties. However, properties that are needed for the initial sorting and filtering, +// like `sortText`, `filterText`, `insertText`, and `textEdit` must be provided in the `textDocument/completion` response and must not be changed during resolve. +func (s *server) Completion(ctx context.Context, params *CompletionParams) (_ *CompletionList, err error) { + s.logger.Debug("call " + MethodTextDocumentCompletion) + defer s.logger.Debug("end "+MethodTextDocumentCompletion, slog.Any("error", err)) + + var result *CompletionList + if err := Call(ctx, s.Conn, MethodTextDocumentCompletion, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// CompletionResolve sends the request from the client to the server to resolve additional information for a given completion item. +func (s *server) CompletionResolve(ctx context.Context, params *CompletionItem) (_ *CompletionItem, err error) { + s.logger.Debug("call " + MethodCompletionItemResolve) + defer s.logger.Debug("end "+MethodCompletionItemResolve, slog.Any("error", err)) + + var result *CompletionItem + if err := Call(ctx, s.Conn, MethodCompletionItemResolve, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Declaration sends the request from the client to the server to resolve the declaration location of a symbol at a given text document position. +// +// The result type LocationLink[] got introduce with version 3.14.0 and depends in the corresponding client capability `clientCapabilities.textDocument.declaration.linkSupport`. +// +// @since 3.14.0. +func (s *server) Declaration(ctx context.Context, params *DeclarationParams) (result []Location, err error) { + s.logger.Debug("call " + MethodTextDocumentDeclaration) + defer s.logger.Debug("end "+MethodTextDocumentDeclaration, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDeclaration, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Definition sends the request from the client to the server to resolve the definition location of a symbol at a given text document position. +// +// The result type `[]LocationLink` got introduce with version 3.14.0 and depends in the corresponding client capability `clientCapabilities.textDocument.definition.linkSupport`. +// +// @since 3.14.0. +func (s *server) Definition(ctx context.Context, params *DefinitionParams) (result []Location, err error) { + s.logger.Debug("call " + MethodTextDocumentDefinition) + defer s.logger.Debug("end "+MethodTextDocumentDefinition, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDefinition, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DidChange sends the notification from the client to the server to signal changes to a text document. +// +// In 2.0 the shape of the params has changed to include proper version numbers and language ids. +func (s *server) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) (err error) { + s.logger.Debug("notify " + MethodTextDocumentDidChange) + defer s.logger.Debug("end "+MethodTextDocumentDidChange, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodTextDocumentDidChange, params) +} + +// DidChangeConfiguration sends the notification from the client to the server to signal the change of configuration settings. +func (s *server) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) (err error) { + s.logger.Debug("call " + MethodWorkspaceDidChangeConfiguration) + defer s.logger.Debug("end "+MethodWorkspaceDidChangeConfiguration, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodWorkspaceDidChangeConfiguration, params) +} + +// DidChangeWatchedFiles sends the notification from the client to the server when the client detects changes to files watched by the language client. +// +// It is recommended that servers register for these file events using the registration mechanism. +// In former implementations clients pushed file events without the server actively asking for it. +func (s *server) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) (err error) { + s.logger.Debug("call " + MethodWorkspaceDidChangeWatchedFiles) + defer s.logger.Debug("end "+MethodWorkspaceDidChangeWatchedFiles, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodWorkspaceDidChangeWatchedFiles, params) +} + +// DidChangeWorkspaceFolders sents the notification from the client to the server to inform the server about workspace folder configuration changes. +// +// The notification is sent by default if both ServerCapabilities/workspace/workspaceFolders and ClientCapabilities/workspace/workspaceFolders are true; +// or if the server has registered itself to receive this notification. +// To register for the workspace/didChangeWorkspaceFolders send a client/registerCapability request from the server to the client. +// +// The registration parameter must have a registrations item of the following form, where id is a unique id used to unregister the capability (the example uses a UUID). +func (s *server) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) (err error) { + s.logger.Debug("call " + MethodWorkspaceDidChangeWorkspaceFolders) + defer s.logger.Debug("end "+MethodWorkspaceDidChangeWorkspaceFolders, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodWorkspaceDidChangeWorkspaceFolders, params) +} + +// DidClose sends the notification from the client to the server when the document got closed in the client. +// +// The document’s truth now exists where the document’s Uri points to (e.g. if the document’s Uri is a file Uri the truth now exists on disk). +// As with the open notification the close notification is about managing the document’s content. +// Receiving a close notification doesn’t mean that the document was open in an editor before. +// +// A close notification requires a previous open notification to be sent. +// Note that a server’s ability to fulfill requests is independent of whether a text document is open or closed. +func (s *server) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) (err error) { + s.logger.Debug("call " + MethodTextDocumentDidClose) + defer s.logger.Debug("end "+MethodTextDocumentDidClose, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodTextDocumentDidClose, params) +} + +// DidOpen sends the open notification from the client to the server to signal newly opened text documents. +// +// The document’s truth is now managed by the client and the server must not try to read the document’s truth using the document’s Uri. +// Open in this sense means it is managed by the client. It doesn’t necessarily mean that its content is presented in an editor. +// +// An open notification must not be sent more than once without a corresponding close notification send before. +// This means open and close notification must be balanced and the max open count for a particular textDocument is one. +// Note that a server’s ability to fulfill requests is independent of whether a text document is open or closed. +func (s *server) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) (err error) { + s.logger.Debug("call " + MethodTextDocumentDidOpen) + defer s.logger.Debug("end "+MethodTextDocumentDidOpen, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodTextDocumentDidOpen, params) +} + +// DidSave sends the notification from the client to the server when the document was saved in the client. +func (s *server) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) (err error) { + s.logger.Debug("call " + MethodTextDocumentDidSave) + defer s.logger.Debug("end "+MethodTextDocumentDidSave, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodTextDocumentDidSave, params) +} + +// DocumentColor sends the request from the client to the server to list all color references found in a given text document. +// +// Along with the range, a color value in RGB is returned. +// +// Clients can use the result to decorate color references in an editor. +// For example: +// +// - Color boxes showing the actual color next to the reference +// - Show a color picker when a color reference is edited. +func (s *server) DocumentColor(ctx context.Context, params *DocumentColorParams) (result []ColorInformation, err error) { + s.logger.Debug("call " + MethodTextDocumentDocumentColor) + defer s.logger.Debug("end "+MethodTextDocumentDocumentColor, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDocumentColor, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DocumentHighlight sends the request is from the client to the server to resolve a document highlights for a given text document position. +// +// For programming languages this usually highlights all references to the symbol scoped to this file. +// However we kept ‘textDocument/documentHighlight’ and ‘textDocument/references’ separate requests since the first one is allowed to be more fuzzy. +// +// Symbol matches usually have a `DocumentHighlightKind` of `Read` or `Write` whereas fuzzy or textual matches use `Text` as the kind. +func (s *server) DocumentHighlight(ctx context.Context, params *DocumentHighlightParams) (result []DocumentHighlight, err error) { + s.logger.Debug("call " + MethodTextDocumentDocumentHighlight) + defer s.logger.Debug("end "+MethodTextDocumentDocumentHighlight, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDocumentHighlight, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DocumentLink sends the request from the client to the server to request the location of links in a document. +func (s *server) DocumentLink(ctx context.Context, params *DocumentLinkParams) (result []DocumentLink, err error) { + s.logger.Debug("call " + MethodTextDocumentDocumentLink) + defer s.logger.Debug("end "+MethodTextDocumentDocumentLink, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDocumentLink, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DocumentLinkResolve sends the request from the client to the server to resolve the target of a given document link. +func (s *server) DocumentLinkResolve(ctx context.Context, params *DocumentLink) (_ *DocumentLink, err error) { + s.logger.Debug("call " + MethodDocumentLinkResolve) + defer s.logger.Debug("end "+MethodDocumentLinkResolve, slog.Any("error", err)) + + var result *DocumentLink + if err := Call(ctx, s.Conn, MethodDocumentLinkResolve, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DocumentSymbol sends the request from the client to the server to return a flat list of all symbols found in a given text document. +// +// Neither the symbol’s location range nor the symbol’s container name should be used to infer a hierarchy. +func (s *server) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) (result []SymbolInformationOrDocumentSymbol, err error) { + s.logger.Debug("call " + MethodTextDocumentDocumentSymbol) + defer s.logger.Debug("end "+MethodTextDocumentDocumentSymbol, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentDocumentSymbol, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// ExecuteCommand sends the request from the client to the server to trigger command execution on the server. +// +// In most cases the server creates a `WorkspaceEdit` structure and applies the changes to the workspace using the +// request `workspace/applyEdit` which is sent from the server to the client. +func (s *server) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (result any, err error) { + s.logger.Debug("call " + MethodWorkspaceExecuteCommand) + defer s.logger.Debug("end "+MethodWorkspaceExecuteCommand, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodWorkspaceExecuteCommand, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// FoldingRanges sends the request from the client to the server to return all folding ranges found in a given text document. +// +// @since version 3.10.0. +func (s *server) FoldingRanges(ctx context.Context, params *FoldingRangeParams) (result []FoldingRange, err error) { + s.logger.Debug("call " + MethodTextDocumentFoldingRange) + defer s.logger.Debug("end "+MethodTextDocumentFoldingRange, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentFoldingRange, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Formatting sends the request from the client to the server to format a whole document. +func (s *server) Formatting(ctx context.Context, params *DocumentFormattingParams) (result []TextEdit, err error) { + s.logger.Debug("call " + MethodTextDocumentFormatting) + defer s.logger.Debug("end "+MethodTextDocumentFormatting, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentFormatting, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Hover sends the request is from the client to the server to request hover information at a given text document position. +func (s *server) Hover(ctx context.Context, params *HoverParams) (_ *Hover, err error) { + s.logger.Debug("call " + MethodTextDocumentHover) + defer s.logger.Debug("end "+MethodTextDocumentHover, slog.Any("error", err)) + + var result *Hover + if err := Call(ctx, s.Conn, MethodTextDocumentHover, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Implementation sends the request from the client to the server to resolve the implementation location of a symbol at a given text document position. +// +// The result type `[]LocationLink` got introduce with version 3.14.0 and depends in the corresponding client capability `clientCapabilities.implementation.typeDefinition.linkSupport`. +func (s *server) Implementation(ctx context.Context, params *ImplementationParams) (result []Location, err error) { + s.logger.Debug("call " + MethodTextDocumentImplementation) + defer s.logger.Debug("end "+MethodTextDocumentImplementation, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentImplementation, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// OnTypeFormatting sends the request from the client to the server to format parts of the document during typing. +func (s *server) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) (result []TextEdit, err error) { + s.logger.Debug("call " + MethodTextDocumentOnTypeFormatting) + defer s.logger.Debug("end "+MethodTextDocumentOnTypeFormatting, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentOnTypeFormatting, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// PrepareRename sends the request from the client to the server to setup and test the validity of a rename operation at a given location. +// +// @since version 3.12.0. +func (s *server) PrepareRename(ctx context.Context, params *PrepareRenameParams) (result *Range, err error) { + s.logger.Debug("call " + MethodTextDocumentPrepareRename) + defer s.logger.Debug("end "+MethodTextDocumentPrepareRename, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentPrepareRename, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// RangeFormatting sends the request from the client to the server to format a given range in a document. +func (s *server) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) (result []TextEdit, err error) { + s.logger.Debug("call " + MethodTextDocumentRangeFormatting) + defer s.logger.Debug("end "+MethodTextDocumentRangeFormatting, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentRangeFormatting, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// References sends the request from the client to the server to resolve project-wide references for the symbol denoted by the given text document position. +func (s *server) References(ctx context.Context, params *ReferenceParams) (result []Location, err error) { + s.logger.Debug("call " + MethodTextDocumentReferences) + defer s.logger.Debug("end "+MethodTextDocumentReferences, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentReferences, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Rename sends the request from the client to the server to perform a workspace-wide rename of a symbol. +func (s *server) Rename(ctx context.Context, params *RenameParams) (result *WorkspaceEdit, err error) { + s.logger.Debug("call " + MethodTextDocumentRename) + defer s.logger.Debug("end "+MethodTextDocumentRename, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentRename, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// SignatureHelp sends the request from the client to the server to request signature information at a given cursor position. +func (s *server) SignatureHelp(ctx context.Context, params *SignatureHelpParams) (_ *SignatureHelp, err error) { + s.logger.Debug("call " + MethodTextDocumentSignatureHelp) + defer s.logger.Debug("end "+MethodTextDocumentSignatureHelp, slog.Any("error", err)) + + var result *SignatureHelp + if err := Call(ctx, s.Conn, MethodTextDocumentSignatureHelp, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Symbols sends the request from the client to the server to list project-wide symbols matching the query string. +func (s *server) Symbols(ctx context.Context, params *WorkspaceSymbolParams) (result []SymbolInformation, err error) { + s.logger.Debug("call " + MethodWorkspaceSymbol) + defer s.logger.Debug("end "+MethodWorkspaceSymbol, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodWorkspaceSymbol, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// TypeDefinition sends the request from the client to the server to resolve the type definition location of a symbol at a given text document position. +// +// The result type `[]LocationLink` got introduce with version 3.14.0 and depends in the corresponding client capability `clientCapabilities.textDocument.typeDefinition.linkSupport`. +// +// @since version 3.6.0. +func (s *server) TypeDefinition(ctx context.Context, params *TypeDefinitionParams) (result []Location, err error) { + s.logger.Debug("call " + MethodTextDocumentTypeDefinition) + defer s.logger.Debug("end "+MethodTextDocumentTypeDefinition, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentTypeDefinition, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// WillSave sends the notification from the client to the server before the document is actually saved. +func (s *server) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) (err error) { + s.logger.Debug("call " + MethodTextDocumentWillSave) + defer s.logger.Debug("end "+MethodTextDocumentWillSave, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodTextDocumentWillSave, params) +} + +// WillSaveWaitUntil sends the request from the client to the server before the document is actually saved. +// +// The request can return an array of TextEdits which will be applied to the text document before it is saved. +// Please note that clients might drop results if computing the text edits took too long or if a server constantly fails on this request. +// This is done to keep the save fast and reliable. +func (s *server) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) (result []TextEdit, err error) { + s.logger.Debug("call " + MethodTextDocumentWillSaveWaitUntil) + defer s.logger.Debug("end "+MethodTextDocumentWillSaveWaitUntil, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentWillSaveWaitUntil, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// ShowDocument sends the request from a server to a client to ask the client to display a particular document in the user interface. +// +// @since 3.16.0. +func (s *server) ShowDocument(ctx context.Context, params *ShowDocumentParams) (result *ShowDocumentResult, err error) { + s.logger.Debug("call " + MethodShowDocument) + defer s.logger.Debug("end "+MethodShowDocument, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodShowDocument, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// WillCreateFiles sends the will create files request is sent from the client to the server before files are actually created as long as the creation is triggered from within the client. +// +// The request can return a WorkspaceEdit which will be applied to workspace before the files are created. +// +// Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep creates fast and reliable. +// +// @since 3.16.0. +func (s *server) WillCreateFiles(ctx context.Context, params *CreateFilesParams) (result *WorkspaceEdit, err error) { + s.logger.Debug("call " + MethodWillCreateFiles) + defer s.logger.Debug("end "+MethodWillCreateFiles, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodWillCreateFiles, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DidCreateFiles sends the did create files notification is sent from the client to the server when files were created from within the client. +// +// @since 3.16.0. +func (s *server) DidCreateFiles(ctx context.Context, params *CreateFilesParams) (err error) { + s.logger.Debug("call " + MethodDidCreateFiles) + defer s.logger.Debug("end "+MethodDidCreateFiles, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodDidCreateFiles, params) +} + +// WillRenameFiles sends the will rename files request is sent from the client to the server before files are actually renamed as long as the rename is triggered from within the client. +// +// The request can return a WorkspaceEdit which will be applied to workspace before the files are renamed. +// +// Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep renames fast and reliable. +// +// @since 3.16.0. +func (s *server) WillRenameFiles(ctx context.Context, params *RenameFilesParams) (result *WorkspaceEdit, err error) { + s.logger.Debug("call " + MethodWillRenameFiles) + defer s.logger.Debug("end "+MethodWillRenameFiles, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodWillRenameFiles, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DidRenameFiles sends the did rename files notification is sent from the client to the server when files were renamed from within the client. +// +// @since 3.16.0. +func (s *server) DidRenameFiles(ctx context.Context, params *RenameFilesParams) (err error) { + s.logger.Debug("call " + MethodDidRenameFiles) + defer s.logger.Debug("end "+MethodDidRenameFiles, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodDidRenameFiles, params) +} + +// WillDeleteFiles sends the will delete files request is sent from the client to the server before files are actually deleted as long as the deletion is triggered from within the client. +// +// The request can return a WorkspaceEdit which will be applied to workspace before the files are deleted. +// +// Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep deletes fast and reliable. +// +// @since 3.16.0. +func (s *server) WillDeleteFiles(ctx context.Context, params *DeleteFilesParams) (result *WorkspaceEdit, err error) { + s.logger.Debug("call " + MethodWillDeleteFiles) + defer s.logger.Debug("end "+MethodWillDeleteFiles, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodWillDeleteFiles, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// DidDeleteFiles sends the did delete files notification is sent from the client to the server when files were deleted from within the client. +// +// @since 3.16.0. +func (s *server) DidDeleteFiles(ctx context.Context, params *DeleteFilesParams) (err error) { + s.logger.Debug("call " + MethodDidDeleteFiles) + defer s.logger.Debug("end "+MethodDidDeleteFiles, slog.Any("error", err)) + + return s.Conn.Notify(ctx, MethodDidDeleteFiles, params) +} + +// CodeLensRefresh sent from the server to the client. +// +// Servers can use it to ask clients to refresh the code lenses currently shown in editors. +// As a result the client should ask the server to recompute the code lenses for these editors. +// This is useful if a server detects a configuration change which requires a re-calculation of all code lenses. +// +// Note that the client still has the freedom to delay the re-calculation of the code lenses if for example an editor is currently not visible. +// +// @since 3.16.0. +func (s *server) CodeLensRefresh(ctx context.Context) (err error) { + s.logger.Debug("call " + MethodCodeLensRefresh) + defer s.logger.Debug("end "+MethodCodeLensRefresh, slog.Any("error", err)) + + return Call(ctx, s.Conn, MethodCodeLensRefresh, nil, nil) +} + +// PrepareCallHierarchy sent from the client to the server to return a call hierarchy for the language element of given text document positions. +// +// The call hierarchy requests are executed in two steps: +// 1. first a call hierarchy item is resolved for the given text document position +// 2. for a call hierarchy item the incoming or outgoing call hierarchy items are resolved. +// +// @since 3.16.0. +func (s *server) PrepareCallHierarchy(ctx context.Context, params *CallHierarchyPrepareParams) (result []CallHierarchyItem, err error) { + s.logger.Debug("call " + MethodTextDocumentPrepareCallHierarchy) + defer s.logger.Debug("end "+MethodTextDocumentPrepareCallHierarchy, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodTextDocumentPrepareCallHierarchy, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// IncomingCalls is the request is sent from the client to the server to resolve incoming calls for a given call hierarchy item. +// +// The request doesn’t define its own client and server capabilities. It is only issued if a server registers for the "textDocument/prepareCallHierarchy" request. +// +// @since 3.16.0. +func (s *server) IncomingCalls(ctx context.Context, params *CallHierarchyIncomingCallsParams) (result []CallHierarchyIncomingCall, err error) { + s.logger.Debug("call " + MethodCallHierarchyIncomingCalls) + defer s.logger.Debug("end "+MethodCallHierarchyIncomingCalls, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodCallHierarchyIncomingCalls, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// OutgoingCalls is the request is sent from the client to the server to resolve outgoing calls for a given call hierarchy item. +// +// The request doesn’t define its own client and server capabilities. It is only issued if a server registers for the "textDocument/prepareCallHierarchy" request. +// +// @since 3.16.0. +func (s *server) OutgoingCalls(ctx context.Context, params *CallHierarchyOutgoingCallsParams) (result []CallHierarchyOutgoingCall, err error) { + s.logger.Debug("call " + MethodCallHierarchyOutgoingCalls) + defer s.logger.Debug("end "+MethodCallHierarchyOutgoingCalls, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodCallHierarchyOutgoingCalls, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// SemanticTokensFull is the request is sent from the client to the server to resolve semantic tokens for a given file. +// +// Semantic tokens are used to add additional color information to a file that depends on language specific symbol information. +// +// A semantic token request usually produces a large result. The protocol therefore supports encoding tokens with numbers. +// +// @since 3.16.0. +func (s *server) SemanticTokensFull(ctx context.Context, params *SemanticTokensParams) (result *SemanticTokens, err error) { + s.logger.Debug("call " + MethodSemanticTokensFull) + defer s.logger.Debug("end "+MethodSemanticTokensFull, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodSemanticTokensFull, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// SemanticTokensFullDelta is the request is sent from the client to the server to resolve semantic token delta for a given file. +// +// Semantic tokens are used to add additional color information to a file that depends on language specific symbol information. +// +// A semantic token request usually produces a large result. The protocol therefore supports encoding tokens with numbers. +// +// @since 3.16.0. +func (s *server) SemanticTokensFullDelta(ctx context.Context, params *SemanticTokensDeltaParams) (result any, err error) { + s.logger.Debug("call " + MethodSemanticTokensFullDelta) + defer s.logger.Debug("end "+MethodSemanticTokensFullDelta, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodSemanticTokensFullDelta, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// SemanticTokensRange is the request is sent from the client to the server to resolve semantic token delta for a given file. +// +// When a user opens a file it can be beneficial to only compute the semantic tokens for the visible range (faster rendering of the tokens in the user interface). +// If a server can compute these tokens faster than for the whole file it can provide a handler for the "textDocument/semanticTokens/range" request to handle this case special. +// +// Please note that if a client also announces that it will send the "textDocument/semanticTokens/range" server should implement this request as well to allow for flicker free scrolling and semantic coloring of a minimap. +// +// @since 3.16.0. +func (s *server) SemanticTokensRange(ctx context.Context, params *SemanticTokensRangeParams) (result *SemanticTokens, err error) { + s.logger.Debug("call " + MethodSemanticTokensRange) + defer s.logger.Debug("end "+MethodSemanticTokensRange, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodSemanticTokensRange, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// SemanticTokensRefresh is sent from the server to the client. Servers can use it to ask clients to refresh the editors for which this server provides semantic tokens. +// +// As a result the client should ask the server to recompute the semantic tokens for these editors. +// This is useful if a server detects a project wide configuration change which requires a re-calculation of all semantic tokens. +// +// Note that the client still has the freedom to delay the re-calculation of the semantic tokens if for example an editor is currently not visible. +// +// @since 3.16.0. +func (s *server) SemanticTokensRefresh(ctx context.Context) (err error) { + s.logger.Debug("call " + MethodSemanticTokensRefresh) + defer s.logger.Debug("end "+MethodSemanticTokensRefresh, slog.Any("error", err)) + + return Call(ctx, s.Conn, MethodSemanticTokensRefresh, nil, nil) +} + +// LinkedEditingRange is the linked editing request is sent from the client to the server to return for a given position in a document the range of the symbol at the position and all ranges that have the same content. +// +// Optionally a word pattern can be returned to describe valid contents. +// +// A rename to one of the ranges can be applied to all other ranges if the new content is valid. If no result-specific word pattern is provided, the word pattern from the client’s language configuration is used. +// +// @since 3.16.0. +func (s *server) LinkedEditingRange(ctx context.Context, params *LinkedEditingRangeParams) (result *LinkedEditingRanges, err error) { + s.logger.Debug("call " + MethodLinkedEditingRange) + defer s.logger.Debug("end "+MethodLinkedEditingRange, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodLinkedEditingRange, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Moniker is the request is sent from the client to the server to get the symbol monikers for a given text document position. +// +// An array of Moniker types is returned as response to indicate possible monikers at the given location. +// +// If no monikers can be calculated, an empty array or null should be returned. +// +// @since 3.16.0. +func (s *server) Moniker(ctx context.Context, params *MonikerParams) (result []Moniker, err error) { + s.logger.Debug("call " + MethodMoniker) + defer s.logger.Debug("end "+MethodMoniker, slog.Any("error", err)) + + if err := Call(ctx, s.Conn, MethodMoniker, params, &result); err != nil { + return nil, err + } + + return result, nil +} + +// Request sends a request from the client to the server that non-compliant with the Language Server Protocol specifications. +func (s *server) Request(ctx context.Context, method string, params any) (any, error) { + s.logger.Debug("call " + method) + defer s.logger.Debug("end " + method) + + var result any + if err := Call(ctx, s.Conn, method, params, &result); err != nil { + return nil, err + } + + return result, nil +} diff --git a/templ/lsp/protocol/text.go b/templ/lsp/protocol/text.go new file mode 100644 index 0000000..a67d5c2 --- /dev/null +++ b/templ/lsp/protocol/text.go @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "strconv" +) + +// DidOpenTextDocumentParams params of DidOpenTextDocument notification. +type DidOpenTextDocumentParams struct { + // TextDocument is the document that was opened. + TextDocument TextDocumentItem `json:"textDocument"` +} + +// DidChangeTextDocumentParams params of DidChangeTextDocument notification. +type DidChangeTextDocumentParams struct { + // TextDocument is the document that did change. The version number points + // to the version after all provided content changes have + // been applied. + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + // ContentChanges is the actual content changes. The content changes describe single state changes + // to the document. So if there are two content changes c1 and c2 for a document + // in state S then c1 move the document to S' and c2 to S''. + ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` // []TextDocumentContentChangeEvent | text +} + +// TextDocumentSaveReason represents reasons why a text document is saved. +type TextDocumentSaveReason float64 + +const ( + // TextDocumentSaveReasonManual is the manually triggered, e.g. by the user pressing save, by starting debugging, + // or by an API call. + TextDocumentSaveReasonManual TextDocumentSaveReason = 1 + + // TextDocumentSaveReasonAfterDelay is the automatic after a delay. + TextDocumentSaveReasonAfterDelay TextDocumentSaveReason = 2 + + // TextDocumentSaveReasonFocusOut when the editor lost focus. + TextDocumentSaveReasonFocusOut TextDocumentSaveReason = 3 +) + +// String implements fmt.Stringer. +func (t TextDocumentSaveReason) String() string { + switch t { + case TextDocumentSaveReasonManual: + return "Manual" + case TextDocumentSaveReasonAfterDelay: + return "AfterDelay" + case TextDocumentSaveReasonFocusOut: + return "FocusOut" + default: + return strconv.FormatFloat(float64(t), 'f', -10, 64) + } +} + +// TextDocumentChangeRegistrationOptions describe options to be used when registering for text document change events. +type TextDocumentChangeRegistrationOptions struct { + TextDocumentRegistrationOptions + + // SyncKind how documents are synced to the server. See TextDocumentSyncKind.Full + // and TextDocumentSyncKind.Incremental. + SyncKind TextDocumentSyncKind `json:"syncKind"` +} + +// WillSaveTextDocumentParams is the parameters send in a will save text document notification. +type WillSaveTextDocumentParams struct { + // TextDocument is the document that will be saved. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Reason is the 'TextDocumentSaveReason'. + Reason TextDocumentSaveReason `json:"reason,omitempty"` +} + +// DidSaveTextDocumentParams params of DidSaveTextDocument notification. +type DidSaveTextDocumentParams struct { + // Text optional the content when saved. Depends on the includeText value + // when the save notification was requested. + Text string `json:"text,omitempty"` + + // TextDocument is the document that was saved. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// TextDocumentContentChangeEvent an event describing a change to a text document. If range and rangeLength are omitted +// the new text is considered to be the full content of the document. +type TextDocumentContentChangeEvent struct { + // Range is the range of the document that changed. + Range *Range `json:"range,omitempty"` + + // RangeLength is the length of the range that got replaced. + RangeLength uint32 `json:"rangeLength,omitempty"` + + // Text is the new text of the document. + Text string `json:"text"` +} + +// TextDocumentSaveRegistrationOptions TextDocumentSave Registration options. +type TextDocumentSaveRegistrationOptions struct { + TextDocumentRegistrationOptions + + // IncludeText is the client is supposed to include the content on save. + IncludeText bool `json:"includeText,omitempty"` +} + +// DidCloseTextDocumentParams params of DidCloseTextDocument notification. +type DidCloseTextDocumentParams struct { + // TextDocument the document that was closed. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} diff --git a/templ/lsp/protocol/text_test.go b/templ/lsp/protocol/text_test.go new file mode 100644 index 0000000..3ae55f5 --- /dev/null +++ b/templ/lsp/protocol/text_test.go @@ -0,0 +1,930 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + + "github.com/a-h/templ/lsp/uri" +) + +func TestDidOpenTextDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/basic.go","languageId":"go","version":10,"text":"Go Language"}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go","languageId":"cpp","version":10,"text":"C++ Language"}}` + ) + wantType := DidOpenTextDocumentParams{ + TextDocument: TextDocumentItem{ + URI: uri.File("/path/to/basic.go"), + LanguageID: GoLanguage, + Version: int32(10), + Text: "Go Language", + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidOpenTextDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidOpenTextDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidOpenTextDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidChangeTextDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}]}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}]}` + ) + wantType := DidChangeTextDocumentParams{ + TextDocument: VersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Version: int32(10), + }, + ContentChanges: []TextDocumentContentChangeEvent{ + { + Range: &Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 25, + Character: 3, + }, + }, + RangeLength: 2, + Text: "testText", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidChangeTextDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidChangeTextDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidChangeTextDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentSaveReason_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k TextDocumentSaveReason + want string + }{ + { + name: "Manual", + k: TextDocumentSaveReasonManual, + want: "Manual", + }, + { + name: "AfterDelay", + k: TextDocumentSaveReasonAfterDelay, + want: "AfterDelay", + }, + { + name: "FocusOut", + k: TextDocumentSaveReasonFocusOut, + want: "FocusOut", + }, + { + name: "Unknown", + k: TextDocumentSaveReason(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("TextDocumentSaveReason.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestTextDocumentContentChangeEvent(t *testing.T) { + t.Parallel() + + const ( + want = `{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}` + wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}` + wantReplaceAll = `{"text":"replace all"}` + ) + wantType := TextDocumentContentChangeEvent{ + Range: &Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 25, + Character: 3, + }, + }, + RangeLength: 2, + Text: "testText", + } + wantReplaceAllType := TextDocumentContentChangeEvent{ + Text: "replace all", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field TextDocumentContentChangeEvent + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + { + name: "ReplaceAll", + field: wantReplaceAllType, + want: wantReplaceAll, + wantMarshalErr: false, + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want TextDocumentContentChangeEvent + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentContentChangeEvent + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentChangeRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"syncKind":2}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"syncKind":1}` + ) + wantType := TextDocumentChangeRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + SyncKind: 2, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field TextDocumentChangeRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want TextDocumentChangeRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentChangeRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWillSaveTextDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"},"reason":3}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"reason":1}` + ) + wantType := WillSaveTextDocumentParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + Reason: TextDocumentSaveReasonFocusOut, + } + wantTypeNilAll := WillSaveTextDocumentParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WillSaveTextDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WillSaveTextDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WillSaveTextDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidSaveTextDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"text":"testText","textDocument":{"uri":"file:///path/to/test.go"}}` + wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"text":"invalidText","textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := DidSaveTextDocumentParams{ + Text: "testText", + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + wantTypeNilAll := DidSaveTextDocumentParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidSaveTextDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidSaveTextDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidSaveTextDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestTextDocumentSaveRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"includeText":true}` + wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}]}` + wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"includeText":false}` + ) + wantType := TextDocumentSaveRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + IncludeText: true, + } + wantTypeNilAll := TextDocumentSaveRegistrationOptions{ + TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ + DocumentSelector: DocumentSelector{ + { + Language: "go", + Scheme: "file", + Pattern: "*.go", + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field TextDocumentSaveRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want TextDocumentSaveRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got TextDocumentSaveRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidCloseTextDocumentParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"textDocument":{"uri":"file:///path/to/test.go"}}` + wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"}}` + ) + wantType := DidCloseTextDocumentParams{ + TextDocument: TextDocumentIdentifier{ + URI: uri.File("/path/to/test.go"), + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidCloseTextDocumentParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidCloseTextDocumentParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidCloseTextDocumentParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/protocol/util.go b/templ/lsp/protocol/util.go new file mode 100644 index 0000000..4dc29c4 --- /dev/null +++ b/templ/lsp/protocol/util.go @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// NewVersion returns the int32 pointer converted i. +func NewVersion(i int32) *int32 { + return &i +} diff --git a/templ/lsp/protocol/util_test.go b/templ/lsp/protocol/util_test.go new file mode 100644 index 0000000..22c9bfe --- /dev/null +++ b/templ/lsp/protocol/util_test.go @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "testing" +) + +func TestNewVersion(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + i int32 + }{ + { + name: "Valid", + i: 5000, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + want := NewVersion(tt.i) + if got := NewVersion(tt.i); *got != *want { + t.Errorf("NewVersion(%v) = %v, want %v", tt.i, *got, *want) + } + }) + } +} diff --git a/templ/lsp/protocol/version.go b/templ/lsp/protocol/version.go new file mode 100644 index 0000000..79a27f3 --- /dev/null +++ b/templ/lsp/protocol/version.go @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2018 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +// Version is the version of the language-server-protocol specification being implemented. +const Version = "3.15.3" diff --git a/templ/lsp/protocol/window.go b/templ/lsp/protocol/window.go new file mode 100644 index 0000000..b6af6f4 --- /dev/null +++ b/templ/lsp/protocol/window.go @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import "strconv" + +// ShowMessageParams params of ShowMessage notification. +type ShowMessageParams struct { + // Message is the actual message. + Message string `json:"message"` + + // Type is the message type. + Type MessageType `json:"type"` +} + +// MessageType type of ShowMessageParams type. +type MessageType float64 + +const ( + // MessageTypeError an error message. + MessageTypeError MessageType = 1 + // MessageTypeWarning a warning message. + MessageTypeWarning MessageType = 2 + // MessageTypeInfo an information message. + MessageTypeInfo MessageType = 3 + // MessageTypeLog a log message. + MessageTypeLog MessageType = 4 +) + +// String implements fmt.Stringer. +func (m MessageType) String() string { + switch m { + case MessageTypeError: + return "error" + case MessageTypeWarning: + return "warning" + case MessageTypeInfo: + return "info" + case MessageTypeLog: + return "log" + default: + return strconv.FormatFloat(float64(m), 'f', -10, 64) + } +} + +// Enabled reports whether the level is enabled. +func (m MessageType) Enabled(level MessageType) bool { + return level > 0 && m >= level +} + +// messageTypeMap map of MessageTypes. +var messageTypeMap = map[string]MessageType{ + "error": MessageTypeError, + "warning": MessageTypeWarning, + "info": MessageTypeInfo, + "log": MessageTypeLog, +} + +// ToMessageType converts level to the MessageType. +func ToMessageType(level string) MessageType { + mt, ok := messageTypeMap[level] + if !ok { + return MessageType(0) // unknown + } + + return mt +} + +// ShowMessageRequestParams params of ShowMessage request. +type ShowMessageRequestParams struct { + // Actions is the message action items to present. + Actions []MessageActionItem `json:"actions"` + + // Message is the actual message + Message string `json:"message"` + + // Type is the message type. See {@link MessageType} + Type MessageType `json:"type"` +} + +// MessageActionItem item of ShowMessageRequestParams action. +type MessageActionItem struct { + // Title a short title like 'Retry', 'Open Log' etc. + Title string `json:"title"` +} + +// LogMessageParams params of LogMessage notification. +type LogMessageParams struct { + // Message is the actual message + Message string `json:"message"` + + // Type is the message type. See {@link MessageType} + Type MessageType `json:"type"` +} + +// WorkDoneProgressCreateParams params of WorkDoneProgressCreate request. +// +// @since 3.15.0. +type WorkDoneProgressCreateParams struct { + // Token is the token to be used to report progress. + Token ProgressToken `json:"token"` +} + +// WorkDoneProgressCreateParams params of WorkDoneProgressCancel request. +// +// @since 3.15.0. +type WorkDoneProgressCancelParams struct { + // Token is the token to be used to report progress. + Token ProgressToken `json:"token"` +} diff --git a/templ/lsp/protocol/window_test.go b/templ/lsp/protocol/window_test.go new file mode 100644 index 0000000..1e6f470 --- /dev/null +++ b/templ/lsp/protocol/window_test.go @@ -0,0 +1,793 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "strconv" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" +) + +func TestShowMessageParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"message":"error message","type":1}` + wantUnknown = `{"message":"unknown message","type":0}` + ) + wantType := ShowMessageParams{ + Message: "error message", + Type: MessageTypeError, + } + wantTypeUnkonwn := ShowMessageParams{ + Message: "unknown message", + Type: MessageType(0), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ShowMessageParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantTypeUnkonwn, + want: wantUnknown, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ShowMessageParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantUnknown, + want: wantTypeUnkonwn, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ShowMessageParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestShowMessageRequestParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"actions":[{"title":"Retry"}],"message":"error message","type":1}` + wantUnknown = `{"actions":[{"title":"Retry"}],"message":"unknown message","type":0}` + ) + wantType := ShowMessageRequestParams{ + Actions: []MessageActionItem{ + { + Title: "Retry", + }, + }, + Message: "error message", + Type: MessageTypeError, + } + wantTypeUnkonwn := ShowMessageRequestParams{ + Actions: []MessageActionItem{ + { + Title: "Retry", + }, + }, + Message: "unknown message", + Type: MessageType(0), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field ShowMessageRequestParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantTypeUnkonwn, + want: wantUnknown, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want ShowMessageRequestParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantUnknown, + want: wantTypeUnkonwn, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ShowMessageRequestParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestMessageActionItem(t *testing.T) { + t.Parallel() + + const ( + want = `{"title":"Retry"}` + wantOpenLog = `{"title":"Open Log"}` + ) + wantType := MessageActionItem{ + Title: "Retry", + } + wantTypeOpenLog := MessageActionItem{ + Title: "Open Log", + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field MessageActionItem + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantTypeOpenLog, + want: wantOpenLog, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want MessageActionItem + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantOpenLog, + want: wantTypeOpenLog, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got MessageActionItem + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestLogMessageParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"message":"error message","type":1}` + wantUnknown = `{"message":"unknown message","type":0}` + ) + wantType := LogMessageParams{ + Message: "error message", + Type: MessageTypeError, + } + wantTypeUnknown := LogMessageParams{ + Message: "unknown message", + Type: MessageType(0), + } + + t.Run("Marshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field LogMessageParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantTypeUnknown, + want: wantUnknown, + wantMarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + field string + want LogMessageParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Unknown", + field: wantUnknown, + want: wantTypeUnknown, + wantUnmarshalErr: false, + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got LogMessageParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkDoneProgressCreateParams(t *testing.T) { + t.Parallel() + + const ( + wantToken = int32(1569) + invalidToken = int32(1348) + ) + var ( + wantString = `{"token":"` + strconv.FormatInt(int64(wantToken), 10) + `"}` + wantInvalidString = `{"token":"` + strconv.FormatInt(int64(invalidToken), 10) + `"}` + wantNumber = `{"token":` + strconv.FormatInt(int64(wantToken), 10) + `}` + wantInvalidNumber = `{"token":` + strconv.FormatInt(int64(invalidToken), 10) + `}` + ) + token := NewProgressToken(strconv.FormatInt(int64(wantToken), 10)) + wantTypeString := WorkDoneProgressCreateParams{ + Token: *token, + } + numberToken := NewNumberProgressToken(wantToken) + wantTypeNumber := WorkDoneProgressCreateParams{ + Token: *numberToken, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressCreateParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid/String", + field: wantTypeString, + want: wantString, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Valid/Number", + field: wantTypeNumber, + want: wantNumber, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid/String", + field: wantTypeString, + want: wantInvalidString, + wantMarshalErr: false, + wantErr: true, + }, + { + name: "Invalid/Number", + field: wantTypeNumber, + want: wantInvalidNumber, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressCreateParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid/String", + field: wantString, + want: wantTypeString, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Valid/Number", + field: wantNumber, + want: wantTypeNumber, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid/String", + field: wantInvalidString, + want: wantTypeString, + wantUnmarshalErr: false, + wantErr: true, + }, + { + name: "Invalid/Number", + field: wantInvalidNumber, + want: wantTypeNumber, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressCreateParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(fmt.Sprint(got.Token), strconv.FormatInt(int64(wantToken), 10)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkDoneProgressCancelParams(t *testing.T) { + t.Parallel() + + const ( + wantToken = int32(1569) + invalidToken = int32(1348) + ) + var ( + want = `{"token":` + strconv.FormatInt(int64(wantToken), 10) + `}` + wantInvalid = `{"token":` + strconv.FormatInt(int64(invalidToken), 10) + `}` + ) + token := NewNumberProgressToken(wantToken) + wantType := WorkDoneProgressCancelParams{ + Token: *token, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkDoneProgressCancelParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkDoneProgressCancelParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkDoneProgressCancelParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(fmt.Sprint(got.Token), strconv.FormatInt(int64(wantToken), 10)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestMessageType_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + m MessageType + want string + }{ + { + name: "Error", + m: MessageTypeError, + want: "error", + }, + { + name: "Warning", + m: MessageTypeWarning, + want: "warning", + }, + { + name: "Info", + m: MessageTypeInfo, + want: "info", + }, + { + name: "Log", + m: MessageTypeLog, + want: "log", + }, + { + name: "Unknown", + m: MessageType(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.m.String(); got != tt.want { + t.Errorf("MessageType.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestMessageType_Enabled(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + m MessageType + level MessageType + want bool + }{ + { + name: "ErrorError", + m: MessageTypeError, + level: MessageTypeError, + want: true, + }, + { + name: "ErrorInfo", + m: MessageTypeError, + level: MessageTypeInfo, + want: false, + }, + { + name: "ErrorUnknown", + m: MessageTypeError, + level: MessageType(0), + want: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.m.Enabled(tt.level); got != tt.want { + t.Errorf("MessageType.Enabled(%v) = %v, want %v", tt.level, tt.want, got) + } + }) + } +} + +func TestToMessageType(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + level string + want MessageType + }{ + { + name: "Error", + level: "error", + want: MessageTypeError, + }, + { + name: "Warning", + level: "warning", + want: MessageTypeWarning, + }, + { + name: "Info", + level: "info", + want: MessageTypeInfo, + }, + { + name: "Log", + level: "log", + want: MessageTypeLog, + }, + { + name: "Unknown", + level: "0", + want: MessageType(0), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := ToMessageType(tt.level); got != tt.want { + t.Errorf("ToMessageType(%v) = %v, want %v", tt.level, tt.want, got) + } + }) + } +} diff --git a/templ/lsp/protocol/workspace.go b/templ/lsp/protocol/workspace.go new file mode 100644 index 0000000..4838918 --- /dev/null +++ b/templ/lsp/protocol/workspace.go @@ -0,0 +1,213 @@ +// SPDX-FileCopyrightText: 2019 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "strconv" + + "github.com/a-h/templ/lsp/uri" +) + +// WorkspaceFolder response of Workspace folders request. +type WorkspaceFolder struct { + // URI is the associated URI for this workspace folder. + URI string `json:"uri"` + + // Name is the name of the workspace folder. Used to refer to this + // workspace folder in the user interface. + Name string `json:"name"` +} + +// DidChangeWorkspaceFoldersParams params of DidChangeWorkspaceFolders notification. +type DidChangeWorkspaceFoldersParams struct { + // Event is the actual workspace folder change event. + Event WorkspaceFoldersChangeEvent `json:"event"` +} + +// WorkspaceFoldersChangeEvent is the workspace folder change event. +type WorkspaceFoldersChangeEvent struct { + // Added is the array of added workspace folders + Added []WorkspaceFolder `json:"added"` + + // Removed is the array of the removed workspace folders + Removed []WorkspaceFolder `json:"removed"` +} + +// DidChangeConfigurationParams params of DidChangeConfiguration notification. +type DidChangeConfigurationParams struct { + // Settings is the actual changed settings + Settings any `json:"settings,omitempty"` +} + +// ConfigurationParams params of Configuration request. +type ConfigurationParams struct { + Items []ConfigurationItem `json:"items"` +} + +// ConfigurationItem a ConfigurationItem consists of the configuration section to ask for and an additional scope URI. +// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to the configuration store used be the client. +// So a server might ask for a configuration cpp.formatterOptions but the client stores the configuration in a XML store layout differently. +// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return the setting scoped to the provided resource. +// If the client for example uses EditorConfig to manage its settings the configuration should be returned for the passed resource URI. If the client can’t provide a configuration setting for a given scope then null need to be present in the returned array. +type ConfigurationItem struct { + // ScopeURI is the scope to get the configuration section for. + ScopeURI uri.URI `json:"scopeUri,omitempty"` + + // Section is the configuration section asked for. + Section string `json:"section,omitempty"` +} + +// DidChangeWatchedFilesParams params of DidChangeWatchedFiles notification. +type DidChangeWatchedFilesParams struct { + // Changes is the actual file events. + Changes []*FileEvent `json:"changes,omitempty"` +} + +// FileEvent an event describing a file change. +type FileEvent struct { + // Type is the change type. + Type FileChangeType `json:"type"` + + // URI is the file's URI. + URI uri.URI `json:"uri"` +} + +// FileChangeType is the file event type. +type FileChangeType float64 + +const ( + // FileChangeTypeCreated is the file got created. + FileChangeTypeCreated FileChangeType = 1 + // FileChangeTypeChanged is the file got changed. + FileChangeTypeChanged FileChangeType = 2 + // FileChangeTypeDeleted is the file got deleted. + FileChangeTypeDeleted FileChangeType = 3 +) + +// String implements fmt.Stringer. +func (t FileChangeType) String() string { + switch t { + case FileChangeTypeCreated: + return "Created" + case FileChangeTypeChanged: + return "Changed" + case FileChangeTypeDeleted: + return "Deleted" + default: + return strconv.FormatFloat(float64(t), 'f', -10, 64) + } +} + +// DidChangeWatchedFilesRegistrationOptions describe options to be used when registering for file system change events. +type DidChangeWatchedFilesRegistrationOptions struct { + // Watchers is the watchers to register. + Watchers []FileSystemWatcher `json:"watchers"` +} + +// FileSystemWatcher watchers of DidChangeWatchedFiles Registration options. +type FileSystemWatcher struct { + // GlobPattern is the glob pattern to watch. + // + // Glob patterns can have the following syntax: + // - `*` to match one or more characters in a path segment + // - `?` to match on one character in a path segment + // - `**` to match any number of path segments, including none + // - `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) + // - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + // - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + GlobPattern string `json:"globPattern"` + + // Kind is the kind of events of interest. If omitted it defaults + // to WatchKind.Create | WatchKind.Change | WatchKind.Delete + // which is 7. + Kind WatchKind `json:"kind,omitempty"` +} + +// WatchKind kind of FileSystemWatcher kind. +type WatchKind float64 + +const ( + // WatchKindCreate interested in create events. + WatchKindCreate WatchKind = 1 + + // WatchKindChange interested in change events. + WatchKindChange WatchKind = 2 + + // WatchKindDelete interested in delete events. + WatchKindDelete WatchKind = 4 +) + +// String implements fmt.Stringer. +func (k WatchKind) String() string { + switch k { + case WatchKindCreate: + return "Create" + case WatchKindChange: + return "Change" + case WatchKindDelete: + return "Delete" + default: + return strconv.FormatFloat(float64(k), 'f', -10, 64) + } +} + +// WorkspaceSymbolParams is the parameters of a Workspace Symbol request. +type WorkspaceSymbolParams struct { + WorkDoneProgressParams + PartialResultParams + + // Query a query string to filter symbols by. + // + // Clients may send an empty string here to request all symbols. + Query string `json:"query"` +} + +// ExecuteCommandParams params of Execute a command. +type ExecuteCommandParams struct { + WorkDoneProgressParams + + // Command is the identifier of the actual command handler. + Command string `json:"command"` + + // Arguments that the command should be invoked with. + Arguments []any `json:"arguments,omitempty"` +} + +// ExecuteCommandRegistrationOptions execute command registration options. +type ExecuteCommandRegistrationOptions struct { + // Commands is the commands to be executed on the server + Commands []string `json:"commands"` +} + +// ApplyWorkspaceEditParams params of Applies a WorkspaceEdit. +type ApplyWorkspaceEditParams struct { + // Label an optional label of the workspace edit. This label is + // presented in the user interface for example on an undo + // stack to undo the workspace edit. + Label string `json:"label,omitempty"` + + // Edit is the edits to apply. + Edit WorkspaceEdit `json:"edit"` +} + +// ApplyWorkspaceEditResponse response of Applies a WorkspaceEdit. +type ApplyWorkspaceEditResponse struct { + // Applied indicates whether the edit was applied or not. + Applied bool `json:"applied"` + + // FailureReason an optional textual description for why the edit was not applied. + // This may be used by the server for diagnostic logging or to provide + // a suitable error for a request that triggered the edit. + // + // @since 3.16.0. + FailureReason string `json:"failureReason,omitempty"` + + // FailedChange depending on the client's failure handling strategy "failedChange" + // might contain the index of the change that failed. This property is + // only available if the client signals a "failureHandlingStrategy" + // in its client capabilities. + // + // @since 3.16.0. + FailedChange uint32 `json:"failedChange,omitempty"` +} diff --git a/templ/lsp/protocol/workspace_test.go b/templ/lsp/protocol/workspace_test.go new file mode 100644 index 0000000..f46a26a --- /dev/null +++ b/templ/lsp/protocol/workspace_test.go @@ -0,0 +1,1697 @@ +// SPDX-FileCopyrightText: 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +package protocol + +import ( + "fmt" + "testing" + + "encoding/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/a-h/templ/lsp/uri" +) + +func TestWorkspaceFolder(t *testing.T) { + t.Parallel() + + const ( + want = `{"uri":"/path/to/workspace","name":"testWorkspace"}` + wantInvalid = `{"uri":"/path/to/invalid","name":"invalidWorkspace"}` + ) + wantType := WorkspaceFolder{ + URI: "/path/to/workspace", + Name: "testWorkspace", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkspaceFolder + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkspaceFolder + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceFolder + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidChangeWorkspaceFoldersParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"event":{"added":[{"uri":"/path/to/addedWorkspace","name":"testAddedWorkspace"},{"uri":"/path/to/addedWorkspace2","name":"testAddedWorkspace2"}],"removed":[{"uri":"/path/to/removedWorkspace","name":"testRemovedWorkspace"},{"uri":"/path/to/removedWorkspace2","name":"testRemovedWorkspace2"}]}}` + wantInvalid = `{"event":{"added":[{"uri":"/path/to/addedInvalidWorkspace","name":"invalidAddedWorkspace"},{"uri":"/path/to/addedInvalidWorkspace2","name":"invalidAddedWorkspace2"}],"removed":[{"uri":"/path/to/removedInvalidWorkspace","name":"invalidRemovedWorkspace"},{"uri":"/path/to/removedInvalidWorkspace2","name":"invalidRemovedWorkspace2"}]}}` + ) + wantType := DidChangeWorkspaceFoldersParams{ + Event: WorkspaceFoldersChangeEvent{ + Added: []WorkspaceFolder{ + { + URI: "/path/to/addedWorkspace", + Name: "testAddedWorkspace", + }, + { + URI: "/path/to/addedWorkspace2", + Name: "testAddedWorkspace2", + }, + }, + Removed: []WorkspaceFolder{ + { + URI: "/path/to/removedWorkspace", + Name: "testRemovedWorkspace", + }, + { + URI: "/path/to/removedWorkspace2", + Name: "testRemovedWorkspace2", + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidChangeWorkspaceFoldersParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidChangeWorkspaceFoldersParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidChangeWorkspaceFoldersParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWorkspaceFoldersChangeEvent(t *testing.T) { + t.Parallel() + + const ( + want = `{"added":[{"uri":"/path/to/addedWorkspace","name":"testAddedWorkspace"},{"uri":"/path/to/addedWorkspace2","name":"testAddedWorkspace2"}],"removed":[{"uri":"/path/to/removedWorkspace","name":"testRemovedWorkspace"},{"uri":"/path/to/removedWorkspace2","name":"testRemovedWorkspace2"}]}` + wantInvalid = `{"added":[{"uri":"/path/to/addedInvalidWorkspace","name":"invalidAddedWorkspace"},{"uri":"/path/to/addedInvalidWorkspace2","name":"invalidAddedWorkspace2"}],"removed":[{"uri":"/path/to/removedInvalidWorkspace","name":"invalidRemovedWorkspace"},{"uri":"/path/to/removedInvalidWorkspace2","name":"invalidRemovedWorkspace2"}]}` + ) + wantType := WorkspaceFoldersChangeEvent{ + Added: []WorkspaceFolder{ + { + URI: "/path/to/addedWorkspace", + Name: "testAddedWorkspace", + }, + { + URI: "/path/to/addedWorkspace2", + Name: "testAddedWorkspace2", + }, + }, + Removed: []WorkspaceFolder{ + { + URI: "/path/to/removedWorkspace", + Name: "testRemovedWorkspace", + }, + { + URI: "/path/to/removedWorkspace2", + Name: "testRemovedWorkspace2", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkspaceFoldersChangeEvent + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkspaceFoldersChangeEvent + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceFoldersChangeEvent + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidChangeConfigurationParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"settings":"testSettings"}` + wantNilAll = `{}` + wantInvalid = `{"settings":"invalidSettings"}` + ) + wantType := DidChangeConfigurationParams{ + Settings: "testSettings", + } + wantTypeNilAll := DidChangeConfigurationParams{} + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidChangeConfigurationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidChangeConfigurationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidChangeConfigurationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestConfigurationParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"items":[{"scopeUri":"file:///path/to/test.go","section":"testSection"}]}` + wantNilAll = `{"items":[]}` + wantInvalid = `{"items":[{"scopeUri":"file:///path/to/invalid.go","section":"invalidSection"}]}` + ) + wantType := ConfigurationParams{ + Items: []ConfigurationItem{ + { + ScopeURI: uri.File("/path/to/test.go"), + Section: "testSection", + }, + }, + } + wantTypeNilAll := ConfigurationParams{ + Items: []ConfigurationItem{}, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ConfigurationParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ConfigurationParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ConfigurationParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestConfigurationItem(t *testing.T) { + t.Parallel() + + const ( + want = `{"scopeUri":"file:///path/to/test.go","section":"testSection"}` + wantNilAll = `{}` + wantInvalid = `{"scopeUri":"file:///path/to/invalid.go","section":"invalidSection"}` + ) + wantType := ConfigurationItem{ + ScopeURI: uri.File("/path/to/test.go"), + Section: "testSection", + } + wantTypeNilAll := ConfigurationItem{} + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ConfigurationItem + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ConfigurationItem + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ConfigurationItem + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestDidChangeWatchedFilesParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"changes":[{"type":2,"uri":"file:///path/to/test.go"}]}` + wantNilAll = `{}` + wantInvalid = `{"changes":[{"type":3,"uri":"file:///path/to/invalid.go"}]}` + ) + wantType := DidChangeWatchedFilesParams{ + Changes: []*FileEvent{ + { + Type: FileChangeTypeChanged, + URI: uri.File("/path/to/test.go"), + }, + }, + } + wantTypeNilAll := DidChangeWatchedFilesParams{} + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidChangeWatchedFilesParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidChangeWatchedFilesParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidChangeWatchedFilesParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestFileEvent(t *testing.T) { + t.Parallel() + + const ( + want = `{"type":2,"uri":"file:///path/to/test.go"}` + wantInvalid = `{"type":3,"uri":"file:///path/to/invalid.go"}` + ) + wantType := FileEvent{ + Type: FileChangeTypeChanged, + URI: uri.File("/path/to/test.go"), + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field FileEvent + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want FileEvent + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got FileEvent + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestFileChangeType_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k FileChangeType + want string + }{ + { + name: "Created", + k: FileChangeTypeCreated, + want: "Created", + }, + { + name: "Changed", + k: FileChangeTypeChanged, + want: "Changed", + }, + { + name: "Deleted", + k: FileChangeTypeDeleted, + want: "Deleted", + }, + { + name: "Unknown", + k: FileChangeType(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("FileChangeType.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestDidChangeWatchedFilesRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"watchers":[{"globPattern":"*","kind":2}]}` + wantNilAll = `{"watchers":[{"globPattern":"*"}]}` + wantInvalid = `{"watchers":[{"globPattern":"?","kind":1}]}` + ) + wantType := DidChangeWatchedFilesRegistrationOptions{ + Watchers: []FileSystemWatcher{ + { + GlobPattern: "*", + Kind: WatchKindChange, + }, + }, + } + wantTypeNilAll := DidChangeWatchedFilesRegistrationOptions{ + Watchers: []FileSystemWatcher{ + { + GlobPattern: "*", + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field DidChangeWatchedFilesRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want DidChangeWatchedFilesRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got DidChangeWatchedFilesRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestWatchKind_String(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + k WatchKind + want string + }{ + { + name: "CreateWatch", + k: WatchKindCreate, + want: "Create", + }, + { + name: "ChangeWatch", + k: WatchKindChange, + want: "Change", + }, + { + name: "DeleteWatch", + k: WatchKindDelete, + want: "Delete", + }, + { + name: "Unknown", + k: WatchKind(0), + want: "0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if got := tt.k.String(); got != tt.want { + t.Errorf("WatchKind.String() = %v, want %v", tt.want, got) + } + }) + } +} + +func TestWorkspaceSymbolParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + wantPartialResultToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","partialResultToken":"` + wantPartialResultToken + `","query":"testQuery"}` + wantInvalid = `{"workDoneToken":"` + wantPartialResultToken + `","partialResultToken":"` + wantWorkDoneToken + `","query":"invalidQuery"}` + ) + wantType := WorkspaceSymbolParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + PartialResultParams: PartialResultParams{ + PartialResultToken: NewProgressToken(wantPartialResultToken), + }, + Query: "testQuery", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field WorkspaceSymbolParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want WorkspaceSymbolParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got WorkspaceSymbolParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + + if partialResultToken := got.PartialResultToken; partialResultToken != nil { + if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestExecuteCommandParams(t *testing.T) { + t.Parallel() + + const ( + wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb" + invalidWorkDoneToken = "dd134d84-c134-4d7a-a2a3-f8af3ef4a568" + ) + const ( + want = `{"workDoneToken":"` + wantWorkDoneToken + `","command":"testCommand","arguments":["testArguments"]}` + wantNilAll = `{"command":"testCommand"}` + wantInvalid = `{"workDoneToken":"` + invalidWorkDoneToken + `","command":"invalidCommand","arguments":["invalidArguments"]}` + ) + wantType := ExecuteCommandParams{ + WorkDoneProgressParams: WorkDoneProgressParams{ + WorkDoneToken: NewProgressToken(wantWorkDoneToken), + }, + Command: "testCommand", + Arguments: []any{ + "testArguments", + }, + } + wantTypeNilAll := ExecuteCommandParams{ + Command: "testCommand", + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ExecuteCommandParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ExecuteCommandParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ExecuteCommandParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreTypes(WorkDoneProgressParams{}, PartialResultParams{})); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + + if workDoneToken := got.WorkDoneToken; workDoneToken != nil { + if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + } + }) + } + }) +} + +func TestExecuteCommandRegistrationOptions(t *testing.T) { + t.Parallel() + + const ( + want = `{"commands":["testCommand","testCommand2"]}` + wantInvalid = `{"commands":["invalidCommand"]}` + ) + wantType := ExecuteCommandRegistrationOptions{ + Commands: []string{ + "testCommand", + "testCommand2", + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ExecuteCommandRegistrationOptions + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ExecuteCommandRegistrationOptions + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ExecuteCommandRegistrationOptions + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestApplyWorkspaceEditParams(t *testing.T) { + t.Parallel() + + const ( + want = `{"label":"testLabel","edit":{"changes":{"file:///path/to/basic.go":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}]}}` + wantNilAll = `{"edit":{"changes":{"file:///path/to/basic.go":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic.go","version":10},"edits":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"newText":"foo bar"}]}]}}` + wantInvalid = `{"label":"testLabel","edit":{"changes":{"file:///path/to/basic_gen.go":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]},"documentChanges":[{"textDocument":{"uri":"file:///path/to/basic_gen.go","version":10},"edits":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"newText":"foo bar"}]}]}}` + ) + wantType := ApplyWorkspaceEditParams{ + Label: "testLabel", + Edit: WorkspaceEdit{ + Changes: map[uri.URI][]TextEdit{ + uri.File("/path/to/basic.go"): { + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + DocumentChanges: []TextDocumentEdit{ + { + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + }, + }, + } + wantTypeNilAll := ApplyWorkspaceEditParams{ + Edit: WorkspaceEdit{ + Changes: map[uri.URI][]TextEdit{ + uri.File("/path/to/basic.go"): { + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + DocumentChanges: []TextDocumentEdit{ + { + TextDocument: OptionalVersionedTextDocumentIdentifier{ + TextDocumentIdentifier: TextDocumentIdentifier{ + URI: uri.File("/path/to/basic.go"), + }, + Version: NewVersion(int32(10)), + }, + Edits: []TextEdit{ + { + Range: Range{ + Start: Position{ + Line: 25, + Character: 1, + }, + End: Position{ + Line: 27, + Character: 3, + }, + }, + NewText: "foo bar", + }, + }, + }, + }, + }, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ApplyWorkspaceEditParams + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantTypeNilAll, + want: wantNilAll, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ApplyWorkspaceEditParams + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "ValidNilAll", + field: wantNilAll, + want: wantTypeNilAll, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ApplyWorkspaceEditParams + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} + +func TestApplyWorkspaceEditResponse(t *testing.T) { + t.Parallel() + + const ( + want = `{"applied":true,"failureReason":"testFailureReason","failedChange":1}` + wantInvalid = `{"applied":false}` + ) + wantType := ApplyWorkspaceEditResponse{ + Applied: true, + FailureReason: "testFailureReason", + FailedChange: 1, + } + + t.Run("Marshal", func(t *testing.T) { + tests := []struct { + name string + field ApplyWorkspaceEditResponse + want string + wantMarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: wantType, + want: want, + wantMarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantType, + want: wantInvalid, + wantMarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := json.Marshal(&tt.field) + if (err != nil) != tt.wantMarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) + + t.Run("Unmarshal", func(t *testing.T) { + tests := []struct { + name string + field string + want ApplyWorkspaceEditResponse + wantUnmarshalErr bool + wantErr bool + }{ + { + name: "Valid", + field: want, + want: wantType, + wantUnmarshalErr: false, + wantErr: false, + }, + { + name: "Invalid", + field: wantInvalid, + want: wantType, + wantUnmarshalErr: false, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + var got ApplyWorkspaceEditResponse + if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { + t.Fatal(err) + } + + if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { + t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) + } + }) + } + }) +} diff --git a/templ/lsp/uri/uri.go b/templ/lsp/uri/uri.go new file mode 100644 index 0000000..454dd6e --- /dev/null +++ b/templ/lsp/uri/uri.go @@ -0,0 +1,192 @@ +// Copyright 2019 The Go Language Server Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uri + +import ( + "errors" + "fmt" + "net/url" + "path/filepath" + "runtime" + "strings" + "unicode" +) + +const ( + // FileScheme schema of filesystem path. + FileScheme = "file" + + // HTTPScheme schema of http. + HTTPScheme = "http" + + // HTTPSScheme schema of https. + HTTPSScheme = "https" +) + +const ( + hierPart = "://" +) + +// URI Uniform Resource Identifier (URI) https://tools.ietf.org/html/rfc3986. +// +// This class is a simple parser which creates the basic component parts +// (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation +// and encoding. +// +// foo://example.com:8042/over/there?name=ferret#nose +// \_/ \______________/\_________/ \_________/ \__/ +// | | | | | +// scheme authority path query fragment +// | _____________________|__ +// / \ / \ +// urn:example:animal:ferret:nose +type URI string + +// Filename returns the file path for the given URI. +// It is an error to call this on a URI that is not a valid filename. +func (u URI) Filename() string { + filename, err := filename(u) + if err != nil { + panic(err) + } + + return filepath.FromSlash(filename) +} + +func filename(uri URI) (string, error) { + u, err := url.ParseRequestURI(string(uri)) + if err != nil { + return "", fmt.Errorf("failed to parse request URI: %w", err) + } + + if u.Scheme != FileScheme { + return "", fmt.Errorf("only file URIs are supported, got %v", u.Scheme) + } + + if isWindowsDriveURI(u.Path) { + u.Path = u.Path[1:] + } + + return u.Path, nil +} + +// New parses and creates a new URI from s. +func New(s string) URI { + if u, err := url.PathUnescape(s); err == nil { + s = u + } + + if strings.HasPrefix(s, FileScheme+hierPart) { + return URI(s) + } + + return File(s) +} + +// File parses and creates a new filesystem URI from path. +func File(path string) URI { + const goRootPragma = "$GOROOT" + if len(path) >= len(goRootPragma) && strings.EqualFold(goRootPragma, path[:len(goRootPragma)]) { + path = runtime.GOROOT() + path[len(goRootPragma):] + } + + if !isWindowsDrivePath(path) { + if abs, err := filepath.Abs(path); err == nil { + path = abs + } + } + + if isWindowsDrivePath(path) { + path = "/" + path + } + + path = filepath.ToSlash(path) + u := url.URL{ + Scheme: FileScheme, + Path: path, + } + + return URI(u.String()) +} + +// Parse parses and creates a new URI from s. +func Parse(s string) (u URI, err error) { + us, err := url.Parse(s) + if err != nil { + return u, fmt.Errorf("url.Parse: %w", err) + } + + switch us.Scheme { + case FileScheme: + ut := url.URL{ + Scheme: FileScheme, + Path: us.Path, + RawPath: filepath.FromSlash(us.Path), + } + u = URI(ut.String()) + + case HTTPScheme, HTTPSScheme: + ut := url.URL{ + Scheme: us.Scheme, + Host: us.Host, + Path: us.Path, + RawQuery: us.Query().Encode(), + Fragment: us.Fragment, + } + u = URI(ut.String()) + + default: + return u, errors.New("unknown scheme") + } + + return +} + +// From returns the new URI from args. +func From(scheme, authority, path, query, fragment string) URI { + switch scheme { + case FileScheme: + u := url.URL{ + Scheme: FileScheme, + Path: path, + RawPath: filepath.FromSlash(path), + } + return URI(u.String()) + + case HTTPScheme, HTTPSScheme: + u := url.URL{ + Scheme: scheme, + Host: authority, + Path: path, + RawQuery: url.QueryEscape(query), + Fragment: fragment, + } + return URI(u.String()) + + default: + panic(fmt.Sprintf("unknown scheme: %s", scheme)) + } +} + +// isWindowsDrivePath returns true if the file path is of the form used by Windows. +// +// We check if the path begins with a drive letter, followed by a ":". +func isWindowsDrivePath(path string) bool { + if len(path) < 4 { + return false + } + return unicode.IsLetter(rune(path[0])) && path[1] == ':' +} + +// isWindowsDriveURI returns true if the file URI is of the format used by +// Windows URIs. The url.Parse package does not specially handle Windows paths +// (see https://golang.org/issue/6027). We check if the URI path has +// a drive prefix (e.g. "/C:"). If so, we trim the leading "/". +func isWindowsDriveURI(uri string) bool { + if len(uri) < 4 { + return false + } + return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':' +} diff --git a/templ/lsp/uri/uri_test.go b/templ/lsp/uri/uri_test.go new file mode 100644 index 0000000..322a43c --- /dev/null +++ b/templ/lsp/uri/uri_test.go @@ -0,0 +1,142 @@ +// Copyright 2019 The Go Language Server Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uri + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestFile(t *testing.T) { + tests := []struct { + name string + path string + want URI + wantErr bool + }{ + { + name: "ValidFileScheme", + path: "/users/me/c#-projects/", + want: URI(FileScheme + hierPart + "/users/me/c%23-projects"), + wantErr: false, + }, + { + name: "Invalid", + path: "users-me-c#-projects", + want: URI(""), + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if diff := cmp.Diff(File(tt.path), tt.want); (diff != "") != tt.wantErr { + t.Errorf("%s: (-got, +want)\n%s", tt.name, diff) + } + }) + } +} + +func TestParse(t *testing.T) { + tests := []struct { + name string + s string + want URI + }{ + { + name: "ValidFileScheme", + s: "file://code.visualstudio.com/docs/extensions/overview.md", + want: URI(FileScheme + hierPart + "/docs/extensions/overview.md"), + }, + { + name: "ValidHTTPScheme", + s: "http://code.visualstudio.com/docs/extensions/overview#frag", + want: URI(HTTPScheme + hierPart + "code.visualstudio.com/docs/extensions/overview#frag"), + }, + { + name: "ValidHTTPSScheme", + s: "https://code.visualstudio.com/docs/extensions/overview#frag", + want: URI(HTTPSScheme + hierPart + "code.visualstudio.com/docs/extensions/overview#frag"), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got, err := Parse(tt.s) + if err != nil { + t.Error(err) + return + } + + if diff := cmp.Diff(got, tt.want); diff != "" { + t.Errorf("%s: (-got, +want)\n%s", tt.name, diff) + } + }) + } +} + +func TestFrom(t *testing.T) { + type args struct { + scheme string + authority string + path string + query string + fragment string + } + tests := []struct { + name string + args args + want URI + }{ + { + name: "ValidFileScheme", + args: args{ + scheme: "file", + authority: "example.com", + path: "/over/there", + query: "name=ferret", + fragment: "nose", + }, + want: URI(FileScheme + hierPart + "/over/there"), + }, + { + name: "ValidHTTPScheme", + args: args{ + scheme: "http", + authority: "example.com:8042", + path: "/over/there", + query: "name=ferret", + fragment: "nose", + }, + want: URI(HTTPScheme + hierPart + "example.com:8042/over/there?name%3Dferret#nose"), + }, + { + name: "ValidHTTPSScheme", + args: args{ + scheme: "https", + authority: "example.com:8042", + path: "/over/there", + query: "name=ferret", + fragment: "nose", + }, + want: URI(HTTPSScheme + hierPart + "example.com:8042/over/there?name%3Dferret#nose"), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + if diff := cmp.Diff(From(tt.args.scheme, tt.args.authority, tt.args.path, tt.args.query, tt.args.fragment), tt.want); diff != "" { + t.Errorf("%s: (-got, +want)\n%s", tt.name, diff) + } + }) + } +} diff --git a/templ/lsp/xcontext/xcontext.go b/templ/lsp/xcontext/xcontext.go new file mode 100644 index 0000000..df35beb --- /dev/null +++ b/templ/lsp/xcontext/xcontext.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Go Language Server Authors +// SPDX-License-Identifier: BSD-3-Clause + +// Package xcontext is a package to offer the extra functionality we need +// from contexts that is not available from the standard context package. +package xcontext + +import ( + "context" + "time" +) + +// Detach returns a context that keeps all the values of its parent context +// but detaches from the cancellation and error handling. +func Detach(ctx context.Context) context.Context { return detachedContext{ctx} } + +type detachedContext struct{ parent context.Context } + +func (v detachedContext) Deadline() (time.Time, bool) { return time.Time{}, false } +func (v detachedContext) Done() <-chan struct{} { return nil } +func (v detachedContext) Err() error { return nil } +func (v detachedContext) Value(key any) any { return v.parent.Value(key) } diff --git a/templ/once.go b/templ/once.go new file mode 100644 index 0000000..7860ab8 --- /dev/null +++ b/templ/once.go @@ -0,0 +1,64 @@ +package templ + +import ( + "context" + "io" + "sync/atomic" +) + +// onceHandleIndex is used to identify unique once handles in a program run. +var onceHandleIndex int64 + +type OnceOpt func(*OnceHandle) + +// WithOnceComponent sets the component to be rendered once per context. +// This can be used instead of setting the children of the `Once` method, +// for example, if creating a code component outside of a templ HTML template. +func WithComponent(c Component) OnceOpt { + return func(o *OnceHandle) { + o.c = c + } +} + +// NewOnceHandle creates a OnceHandle used to ensure that the children of its +// `Once` method are only rendered once per context. +func NewOnceHandle(opts ...OnceOpt) *OnceHandle { + oh := &OnceHandle{ + id: atomic.AddInt64(&onceHandleIndex, 1), + } + for _, opt := range opts { + opt(oh) + } + return oh +} + +// OnceHandle is used to ensure that the children of its `Once` method are are only +// rendered once per context. +type OnceHandle struct { + // id is used to identify which instance of the OnceHandle is being used. + // The OnceHandle can't be an empty struct, because: + // + // | Two distinct zero-size variables may + // | have the same address in memory + // + // https://go.dev/ref/spec#Size_and_alignment_guarantees + id int64 + // c is the component to be rendered once per context. + // if c is nil, the children of the `Once` method are rendered. + c Component +} + +// Once returns a component that renders its children once per context. +func (o *OnceHandle) Once() Component { + return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + _, v := getContext(ctx) + if v.getHasBeenRendered(o) { + return nil + } + v.setHasBeenRendered(o) + if o.c != nil { + return o.c.Render(ctx, w) + } + return GetChildren(ctx).Render(ctx, w) + }) +} diff --git a/templ/once_test.go b/templ/once_test.go new file mode 100644 index 0000000..bd48da3 --- /dev/null +++ b/templ/once_test.go @@ -0,0 +1,117 @@ +package templ_test + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +type onceHandleTest struct { + ctx context.Context + expected string +} + +func TestOnceHandle(t *testing.T) { + withHello := templ.WithChildren(context.Background(), templ.Raw("hello")) + tests := []struct { + name string + tests []onceHandleTest + }{ + { + name: "renders nothing without children", + tests: []onceHandleTest{ + { + ctx: context.Background(), + expected: "", + }, + }, + }, + { + name: "children are rendered", + tests: []onceHandleTest{ + { + ctx: templ.WithChildren(context.Background(), templ.Raw("hello")), + expected: "hello", + }, + }, + }, + { + name: "children are rendered once per context", + tests: []onceHandleTest{ + { + ctx: withHello, + expected: "hello", + }, + { + ctx: withHello, + expected: "", + }, + }, + }, + { + name: "different contexts have different once state", + tests: []onceHandleTest{ + { + ctx: templ.WithChildren(context.Background(), templ.Raw("hello")), + expected: "hello", + }, + { + ctx: templ.WithChildren(context.Background(), templ.Raw("hello2")), + expected: "hello2", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := templ.NewOnceHandle().Once() + for i, test := range tt.tests { + t.Run(fmt.Sprintf("render %d/%d", i+1, len(tt.tests)), func(t *testing.T) { + html, err := templ.ToGoHTML(test.ctx, c) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff(test.expected, string(html)); diff != "" { + t.Errorf("unexpected diff:\n%v", diff) + } + }) + } + }) + } + t.Run("each new handle manages different state", func(t *testing.T) { + ctx := templ.WithChildren(context.Background(), templ.Raw("hello")) + h1 := templ.NewOnceHandle() + c1 := h1.Once() + h2 := templ.NewOnceHandle() + c2 := h2.Once() + c3 := h2.Once() + var w strings.Builder + if err := c1.Render(ctx, &w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := c2.Render(ctx, &w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if err := c3.Render(ctx, &w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff("hellohello", w.String()); diff != "" { + t.Errorf("unexpected diff:\n%v", diff) + } + }) + t.Run("a handle can be used to render a specific component", func(t *testing.T) { + ctx := templ.WithChildren(context.Background(), templ.Raw("child")) + o := templ.NewOnceHandle(templ.WithComponent(templ.Raw("c"))).Once() + var w strings.Builder + if err := o.Render(ctx, &w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff("c", w.String()); diff != "" { + t.Errorf("unexpected diff:\n%v", diff) + } + }) +} diff --git a/templ/parser/v2/allocs_test.go b/templ/parser/v2/allocs_test.go new file mode 100644 index 0000000..ab058ab --- /dev/null +++ b/templ/parser/v2/allocs_test.go @@ -0,0 +1,26 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" +) + +func RunParserAllocTest[T any](t *testing.T, p parse.Parser[T], expectOK bool, maxAllocs int64, input string) { + pi := parse.NewInput(input) + actual := testing.AllocsPerRun(4, func() { + pi.Seek(0) + _, ok, err := p.Parse(pi) + if err != nil { + t.Fatalf("error parsing %T: %v", p, err) + } + if ok != expectOK { + t.Fatalf("failed to parse %T", p) + } + }) + + // Run the benchmark. + if int64(actual) > maxAllocs { + t.Fatalf("Expected allocs <= %d, got %d", maxAllocs, int64(actual)) + } +} diff --git a/templ/parser/v2/benchmarks_test.go b/templ/parser/v2/benchmarks_test.go new file mode 100644 index 0000000..1ac7b28 --- /dev/null +++ b/templ/parser/v2/benchmarks_test.go @@ -0,0 +1,34 @@ +package parser + +import ( + _ "embed" + "strings" + "testing" +) + +//go:embed benchmarktestdata/benchmark.txt +var benchmarkTemplate string + +func BenchmarkParse(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + if _, err := ParseString(benchmarkTemplate); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkFormat(b *testing.B) { + b.ReportAllocs() + sb := new(strings.Builder) + for i := 0; i < b.N; i++ { + tf, err := ParseString(benchmarkTemplate) + if err != nil { + b.Fatal(err) + } + if err = tf.Write(sb); err != nil { + b.Fatal(err) + } + sb.Reset() + } +} diff --git a/templ/parser/v2/benchmarktestdata/benchmark.txt b/templ/parser/v2/benchmarktestdata/benchmark.txt new file mode 100644 index 0000000..e7c7ffc --- /dev/null +++ b/templ/parser/v2/benchmarktestdata/benchmark.txt @@ -0,0 +1,18 @@ +package benchmarktestdata + +templ Benchmark() { +
    Hello
    +
    +
    +
    +
    +
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    +
    +
    +
      +
    • Item 1
    • +
    • Item 2
    • +
    • Item 3
    • +
    +} + diff --git a/templ/parser/v2/calltemplateparser.go b/templ/parser/v2/calltemplateparser.go new file mode 100644 index 0000000..3e82a20 --- /dev/null +++ b/templ/parser/v2/calltemplateparser.go @@ -0,0 +1,33 @@ +package parser + +import ( + "github.com/a-h/parse" + "github.com/a-h/templ/parser/v2/goexpression" +) + +var callTemplateExpression callTemplateExpressionParser + +var callTemplateExpressionStart = parse.Or(parse.String("{! "), parse.String("{!")) + +type callTemplateExpressionParser struct{} + +func (p callTemplateExpressionParser) Parse(pi *parse.Input) (n Node, ok bool, err error) { + // Check the prefix first. + if _, ok, err = callTemplateExpressionStart.Parse(pi); err != nil || !ok { + return + } + + // Once we have a prefix, we must have an expression that returns a template. + var r CallTemplateExpression + if r.Expression, err = parseGo("call template expression", pi, goexpression.Expression); err != nil { + return + } + + // Eat the final brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("call template expression: missing closing brace", pi.Position()) + return + } + + return r, true, nil +} diff --git a/templ/parser/v2/calltemplateparser_test.go b/templ/parser/v2/calltemplateparser_test.go new file mode 100644 index 0000000..d4df203 --- /dev/null +++ b/templ/parser/v2/calltemplateparser_test.go @@ -0,0 +1,100 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestCallTemplateExpressionParser(t *testing.T) { + tests := []struct { + name string + input string + expected CallTemplateExpression + }{ + { + name: "call: simple", + input: `{! Other(p.Test) }`, + expected: CallTemplateExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 3, + Line: 0, + Col: 3, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + { + name: "call: simple, missing start space", + input: `{!Other(p.Test) }`, + expected: CallTemplateExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 2, + Line: 0, + Col: 2, + }, + To: Position{ + Index: 15, + Line: 0, + Col: 15, + }, + }, + }, + }, + }, + { + name: "call: simple, missing start and end space", + input: `{!Other(p.Test)}`, + expected: CallTemplateExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 2, + Line: 0, + Col: 2, + }, + To: Position{ + Index: 15, + Line: 0, + Col: 15, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := callTemplateExpression.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Errorf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestCallTemplateParserAllocsSkip(t *testing.T) { + RunParserAllocTest(t, callTemplateExpression, false, 0, ``) +} diff --git a/templ/parser/v2/childrenparser.go b/templ/parser/v2/childrenparser.go new file mode 100644 index 0000000..127537b --- /dev/null +++ b/templ/parser/v2/childrenparser.go @@ -0,0 +1,21 @@ +package parser + +import ( + "github.com/a-h/parse" +) + +var childrenExpressionParser = parse.StringFrom( + openBraceWithOptionalPadding, + parse.OptionalWhitespace, + parse.String("children..."), + parse.OptionalWhitespace, + closeBraceWithOptionalPadding, +) + +var childrenExpression = parse.Func(func(in *parse.Input) (n Node, ok bool, err error) { + _, ok, err = childrenExpressionParser.Parse(in) + if err != nil || !ok { + return + } + return ChildrenExpression{}, true, nil +}) diff --git a/templ/parser/v2/childrenparser_test.go b/templ/parser/v2/childrenparser_test.go new file mode 100644 index 0000000..2789c37 --- /dev/null +++ b/templ/parser/v2/childrenparser_test.go @@ -0,0 +1,56 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestChildrenExpressionParser(t *testing.T) { + var tests = []struct { + name string + input string + expected ChildrenExpression + }{ + { + name: "standard", + input: `{ children...}`, + expected: ChildrenExpression{}, + }, + { + name: "condensed", + input: `{children...}`, + expected: ChildrenExpression{}, + }, + { + name: "extra spaces", + input: `{ children... }`, + expected: ChildrenExpression{}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := childrenExpression.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Errorf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestChildrenExpressionParserAllocsOK(t *testing.T) { + RunParserAllocTest(t, childrenExpression, true, 2, `{ children... }`) +} + +func TestChildrenExpressionParserAllocsSkip(t *testing.T) { + RunParserAllocTest(t, childrenExpression, false, 2, ``) +} diff --git a/templ/parser/v2/conditionalattributeparser.go b/templ/parser/v2/conditionalattributeparser.go new file mode 100644 index 0000000..814de97 --- /dev/null +++ b/templ/parser/v2/conditionalattributeparser.go @@ -0,0 +1,100 @@ +package parser + +import ( + "github.com/a-h/parse" + "github.com/a-h/templ/parser/v2/goexpression" +) + +var conditionalAttribute parse.Parser[ConditionalAttribute] = conditionalAttributeParser{} + +type conditionalAttributeParser struct{} + +func (conditionalAttributeParser) Parse(pi *parse.Input) (r ConditionalAttribute, ok bool, err error) { + start := pi.Index() + + // Strip leading whitespace and look for `if `. + if _, _, err = parse.OptionalWhitespace.Parse(pi); err != nil { + return + } + if !peekPrefix(pi, "if ") { + pi.Seek(start) + return + } + + // Parse the Go if expression. + if r.Expression, err = parseGo("if attribute", pi, goexpression.If); err != nil { + return + } + + // Eat " {\n". + if _, ok, err = openBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("attribute if: unterminated (missing closing '{\n')", pi.PositionAt(start)) + return + } + if _, _, err = parse.OptionalWhitespace.Parse(pi); err != nil { + return + } + + // Read the 'Then' attributes. + // If there's no match, there's a problem reading the attributes. + if r.Then, ok, err = (attributesParser{}).Parse(pi); err != nil || !ok { + err = parse.Error("attribute if: expected attributes in block, but none were found", pi.Position()) + return + } + + if len(r.Then) == 0 { + err = parse.Error("attribute if: invalid content or no attributes were found in the if block", pi.Position()) + return + } + + // Read the optional 'Else' Nodes. + if r.Else, ok, err = attributeElseExpression.Parse(pi); err != nil { + return + } + if ok && len(r.Else) == 0 { + err = parse.Error("attribute if: invalid content or no attributes were found in the else block", pi.Position()) + return + } + + // Clear any optional whitespace. + _, _, _ = parse.OptionalWhitespace.Parse(pi) + + // Read the required closing brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("attribute if: missing end (expected '}')", pi.Position()) + return + } + + return r, true, nil +} + +var attributeElseExpression parse.Parser[[]Attribute] = attributeElseExpressionParser{} + +type attributeElseExpressionParser struct{} + +func (attributeElseExpressionParser) Parse(in *parse.Input) (r []Attribute, ok bool, err error) { + start := in.Index() + + // Strip any initial whitespace. + _, _, _ = parse.OptionalWhitespace.Parse(in) + + // } else { + var endElseParser = parse.All( + parse.Rune('}'), + parse.OptionalWhitespace, + parse.String("else"), + parse.OptionalWhitespace, + parse.Rune('{')) + if _, ok, err = endElseParser.Parse(in); err != nil || !ok { + in.Seek(start) + return + } + + // Else contents + if r, ok, err = (attributesParser{}).Parse(in); err != nil || !ok { + err = parse.Error("attribute if: expected attributes in else block, but none were found", in.Position()) + return + } + + return r, true, nil +} diff --git a/templ/parser/v2/cssparser.go b/templ/parser/v2/cssparser.go new file mode 100644 index 0000000..7d044df --- /dev/null +++ b/templ/parser/v2/cssparser.go @@ -0,0 +1,197 @@ +package parser + +import ( + "github.com/a-h/parse" +) + +// CSS. + +// CSS Parser. +var cssParser = parse.Func(func(pi *parse.Input) (r CSSTemplate, ok bool, err error) { + from := pi.Position() + + r = CSSTemplate{ + Properties: []CSSProperty{}, + } + + // Parse the name. + var exp cssExpression + if exp, ok, err = cssExpressionParser.Parse(pi); err != nil || !ok { + return + } + r.Name = exp.Name + r.Expression = exp.Expression + + for { + var cssProperty CSSProperty + + // Try for an expression CSS declaration. + // background-color: { constants.BackgroundColor }; + cssProperty, ok, err = expressionCSSPropertyParser.Parse(pi) + if err != nil { + return + } + if ok { + r.Properties = append(r.Properties, cssProperty) + continue + } + + // Try for a constant CSS declaration. + // color: #ffffff; + cssProperty, ok, err = constantCSSPropertyParser.Parse(pi) + if err != nil { + return + } + if ok { + r.Properties = append(r.Properties, cssProperty) + continue + } + + // Eat any whitespace. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + // Try for } + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("css property expression: missing closing brace", pi.Position()) + return + } + + r.Range = NewRange(from, pi.Position()) + + return r, true, nil + } +}) + +// css Func() { +type cssExpression struct { + Expression Expression + Name string +} + +var cssExpressionParser = parse.Func(func(pi *parse.Input) (r cssExpression, ok bool, err error) { + start := pi.Index() + + if !peekPrefix(pi, "css ") { + return r, false, nil + } + + // Once we have the prefix, everything to the brace is Go. + // e.g. + // css (x []string) Test() { + // becomes: + // func (x []string) Test() templ.CSSComponent { + if r.Name, r.Expression, err = parseCSSFuncDecl(pi); err != nil { + return r, false, err + } + + // Eat " {\n". + if _, ok, err = parse.All(openBraceWithOptionalPadding, parse.NewLine).Parse(pi); err != nil || !ok { + err = parse.Error("css expression: parameters missing open bracket", pi.PositionAt(start)) + return + } + + return r, true, nil +}) + +// CSS property name parser. +var cssPropertyNameFirst = "abcdefghijklmnopqrstuvwxyz-" +var cssPropertyNameSubsequent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-" +var cssPropertyNameParser = parse.Func(func(in *parse.Input) (name string, ok bool, err error) { + start := in.Position() + var prefix, suffix string + if prefix, ok, err = parse.RuneIn(cssPropertyNameFirst).Parse(in); err != nil || !ok { + return + } + if suffix, ok, err = parse.StringUntil(parse.RuneNotIn(cssPropertyNameSubsequent)).Parse(in); err != nil || !ok { + in.Seek(start.Index) + return + } + if len(suffix)+1 > 128 { + ok = false + err = parse.Error("css property names must be < 128 characters long", in.Position()) + return + } + return prefix + suffix, true, nil +}) + +// background-color: {%= constants.BackgroundColor %}; +var expressionCSSPropertyParser = parse.Func(func(pi *parse.Input) (r ExpressionCSSProperty, ok bool, err error) { + start := pi.Index() + + // Optional whitespace. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + // Property name. + if r.Name, ok, err = cssPropertyNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + // : + if _, ok, err = parse.All(parse.OptionalWhitespace, parse.Rune(':'), parse.OptionalWhitespace).Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + + // { string } + var se Node + if se, ok, err = stringExpression.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + r.Value = se.(StringExpression) + + // ; + if _, ok, err = parse.String(";").Parse(pi); err != nil || !ok { + err = parse.Error("missing expected semicolon (;)", pi.Position()) + return + } + // \n + if _, ok, err = parse.NewLine.Parse(pi); err != nil || !ok { + err = parse.Error("missing expected linebreak", pi.Position()) + return + } + + return r, true, nil +}) + +// background-color: #ffffff; +var constantCSSPropertyParser = parse.Func(func(pi *parse.Input) (r ConstantCSSProperty, ok bool, err error) { + start := pi.Index() + + // Optional whitespace. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + // Property name. + if r.Name, ok, err = cssPropertyNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + // : + if _, ok, err = parse.All(parse.OptionalWhitespace, parse.Rune(':'), parse.OptionalWhitespace).Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + + // Everything until ';\n' + untilEnd := parse.All( + parse.OptionalWhitespace, + parse.Rune(';'), + parse.NewLine, + ) + if r.Value, ok, err = parse.StringUntil(untilEnd).Parse(pi); err != nil || !ok { + err = parse.Error("missing expected semicolon and linebreak (;\\n", pi.Position()) + return + } + + // Chomp the ;\n + if _, ok, err = untilEnd.Parse(pi); err != nil || !ok { + err = parse.Error("failed to chomp semicolon and linebreak (;\\n)", pi.Position()) + return + } + + return r, true, nil +}) diff --git a/templ/parser/v2/cssparser_test.go b/templ/parser/v2/cssparser_test.go new file mode 100644 index 0000000..0c89aa9 --- /dev/null +++ b/templ/parser/v2/cssparser_test.go @@ -0,0 +1,337 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestExpressionCSSPropertyParser(t *testing.T) { + tests := []struct { + name string + input string + expected ExpressionCSSProperty + }{ + { + name: "css: single constant property", + input: `background-color: { constants.BackgroundColor };`, + expected: ExpressionCSSProperty{ + Name: "background-color", + Value: StringExpression{ + Expression: Expression{ + Value: "constants.BackgroundColor", + Range: Range{ + From: Position{ + Index: 20, + Line: 0, + Col: 20, + }, + To: Position{ + Index: 45, + Line: 0, + Col: 45, + }, + }, + }, + }, + }, + }, + { + name: "css: single constant property with windows newlines", + input: "background-color:\r\n{ constants.BackgroundColor };\r\n", + expected: ExpressionCSSProperty{ + Name: "background-color", + Value: StringExpression{ + Expression: Expression{ + Value: "constants.BackgroundColor", + Range: Range{ + From: Position{ + Index: 21, + Line: 1, + Col: 2, + }, + To: Position{ + Index: 46, + Line: 1, + Col: 27, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input + "\n") + result, ok, err := expressionCSSPropertyParser.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestConstantCSSPropertyParser(t *testing.T) { + tests := []struct { + name string + input string + expected ConstantCSSProperty + }{ + { + name: "css: single constant property", + input: `background-color: #ffffff;`, + expected: ConstantCSSProperty{ + Name: "background-color", + Value: "#ffffff", + }, + }, + { + name: "css: single constant webkit property", + input: `-webkit-text-stroke-color: #ffffff;`, + expected: ConstantCSSProperty{ + Name: "-webkit-text-stroke-color", + Value: "#ffffff", + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input + "\n") + result, ok, err := constantCSSPropertyParser.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestCSSParser(t *testing.T) { + tests := []struct { + name string + input string + expected CSSTemplate + }{ + { + name: "css: no parameters, no content", + input: `css Name() { +}`, + expected: CSSTemplate{ + Name: "Name", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 14, Line: 1, Col: 1}, + }, + Expression: Expression{ + Value: "Name()", + Range: Range{ + From: Position{ + Index: 4, + Line: 0, + Col: 4, + }, + To: Position{ + Index: 10, + Line: 0, + Col: 10, + }, + }, + }, + Properties: []CSSProperty{}, + }, + }, + { + name: "css: without spaces", + input: `css Name() { +}`, + expected: CSSTemplate{ + Name: "Name", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 14, Line: 1, Col: 1}, + }, + Expression: Expression{ + Value: "Name()", + Range: Range{ + From: Position{ + Index: 4, + Line: 0, + Col: 4, + }, + To: Position{ + Index: 10, + Line: 0, + Col: 10, + }, + }, + }, + Properties: []CSSProperty{}, + }, + }, + { + name: "css: single constant property", + input: `css Name() { +background-color: #ffffff; +}`, + expected: CSSTemplate{ + Name: "Name", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 41, Line: 2, Col: 1}, + }, + Expression: Expression{ + Value: "Name()", + Range: Range{ + From: Position{ + Index: 4, + Line: 0, + Col: 4, + }, + To: Position{ + Index: 10, + Line: 0, + Col: 10, + }, + }, + }, + Properties: []CSSProperty{ + ConstantCSSProperty{ + Name: "background-color", + Value: "#ffffff", + }, + }, + }, + }, + { + name: "css: single expression property", + input: `css Name() { +background-color: { constants.BackgroundColor }; +}`, + expected: CSSTemplate{ + Name: "Name", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 63, Line: 2, Col: 1}, + }, + Expression: Expression{ + Value: "Name()", + Range: Range{ + From: Position{ + Index: 4, + Line: 0, + Col: 4, + }, + To: Position{ + Index: 10, + Line: 0, + Col: 10, + }, + }, + }, + Properties: []CSSProperty{ + ExpressionCSSProperty{ + Name: "background-color", + Value: StringExpression{ + Expression: Expression{ + Value: "constants.BackgroundColor", + Range: Range{ + From: Position{ + Index: 33, + Line: 1, + Col: 20, + }, + To: Position{ + Index: 58, + Line: 1, + Col: 45, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "css: single expression with parameter", + input: `css Name(prop string) { +background-color: { prop }; +}`, + expected: CSSTemplate{ + Name: "Name", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 53, Line: 2, Col: 1}, + }, + Expression: Expression{ + Value: "Name(prop string)", + Range: Range{ + From: Position{ + Index: 4, + Line: 0, + Col: 4, + }, + To: Position{ + Index: 21, + Line: 0, + Col: 21, + }, + }, + }, + Properties: []CSSProperty{ + ExpressionCSSProperty{ + Name: "background-color", + Value: StringExpression{ + Expression: Expression{ + Value: "prop", + Range: Range{ + From: Position{ + Index: 44, + Line: 1, + Col: 20, + }, + To: Position{ + Index: 48, + Line: 1, + Col: 24, + }, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := cssParser.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/parser/v2/diagnostics.go b/templ/parser/v2/diagnostics.go new file mode 100644 index 0000000..8f36653 --- /dev/null +++ b/templ/parser/v2/diagnostics.go @@ -0,0 +1,64 @@ +package parser + +import ( + "errors" +) + +type diagnoser func(Node) ([]Diagnostic, error) + +// Diagnostic for template file. +type Diagnostic struct { + Message string + Range Range +} + +func walkTemplate(t TemplateFile, f func(Node) bool) { + for _, n := range t.Nodes { + hn, ok := n.(HTMLTemplate) + if !ok { + continue + } + walkNodes(hn.Children, f) + } +} +func walkNodes(t []Node, f func(Node) bool) { + for _, n := range t { + if !f(n) { + continue + } + if h, ok := n.(CompositeNode); ok { + walkNodes(h.ChildNodes(), f) + } + } +} + +var diagnosers = []diagnoser{ + useOfLegacyCallSyntaxDiagnoser, +} + +func Diagnose(t TemplateFile) ([]Diagnostic, error) { + var diags []Diagnostic + var errs error + walkTemplate(t, func(n Node) bool { + for _, d := range diagnosers { + diag, err := d(n) + if err != nil { + errs = errors.Join(errs, err) + return false + } + diags = append(diags, diag...) + } + return true + }) + return diags, errs +} + +func useOfLegacyCallSyntaxDiagnoser(n Node) ([]Diagnostic, error) { + if c, ok := n.(CallTemplateExpression); ok { + return []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: c.Expression.Range, + }}, nil + } + return nil, nil +} diff --git a/templ/parser/v2/diagnostics_test.go b/templ/parser/v2/diagnostics_test.go new file mode 100644 index 0000000..e0a7b45 --- /dev/null +++ b/templ/parser/v2/diagnostics_test.go @@ -0,0 +1,153 @@ +package parser + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestDiagnose(t *testing.T) { + tests := []struct { + name string + template string + want []Diagnostic + }{ + { + name: "no diagnostics", + template: ` +package main + +templ template () { +

    Hello, World!

    +}`, + want: nil, + }, + + // useOfLegacyCallSyntaxDiagnoser + + { + name: "useOfLegacyCallSyntaxDiagnoser: template root", + template: ` +package main + +templ template () { + {! templ.Raw("foo") } +}`, + want: []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{39, 4, 4}, Position{55, 4, 20}}, + }}, + }, + { + name: "useOfLegacyCallSyntaxDiagnoser: in div", + template: ` +package main + +templ template () { +
    + {! templ.Raw("foo") } +
    +}`, + want: []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{47, 5, 5}, Position{63, 5, 21}}, + }}, + }, + { + name: "useOfLegacyCallSyntaxDiagnoser: in if", + template: ` +package main + +templ template () { + if true { + {! templ.Raw("foo") } + } +}`, + want: []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{51, 5, 5}, Position{67, 5, 21}}, + }}, + }, + { + name: "useOfLegacyCallSyntaxDiagnoser: in for", + template: ` +package main + +templ template () { + for i := range x { + {! templ.Raw("foo") } + } +}`, + want: []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{60, 5, 5}, Position{76, 5, 21}}, + }}, + }, + { + name: "useOfLegacyCallSyntaxDiagnoser: in switch", + template: ` +package main + +templ template () { + switch x { + case 1: + {! templ.Raw("foo") } + default: + {! x } + } +}`, + want: []Diagnostic{ + { + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{61, 6, 5}, Position{77, 6, 21}}, + }, + { + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{95, 8, 5}, Position{96, 8, 6}}, + }, + }, + }, + { + name: "useOfLegacyCallSyntaxDiagnoser: in block", + template: ` +package main + +templ template () { + @layout("Home") { + {! templ.Raw("foo") } + } +}`, + want: []Diagnostic{{ + Message: "`{! foo }` syntax is deprecated. Use `@foo` syntax instead. Run `templ fmt .` to fix all instances.", + Range: Range{Position{59, 5, 5}, Position{75, 5, 21}}, + }}, + }, + { + name: "voidElementWithChildrenDiagnoser: no diagnostics", + template: ` +package main + +templ template () { +
    + +
    +}`, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tf, err := ParseString(tt.template) + if err != nil { + t.Fatalf("ParseTemplateFile() error = %v", err) + } + got, err := Diagnose(tf) + if err != nil { + t.Fatalf("Diagnose() error = %v", err) + } + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("Diagnose() mismatch (-got +want):\n%s", diff) + } + }) + } +} diff --git a/templ/parser/v2/doctypeparser.go b/templ/parser/v2/doctypeparser.go new file mode 100644 index 0000000..069d2fc --- /dev/null +++ b/templ/parser/v2/doctypeparser.go @@ -0,0 +1,32 @@ +package parser + +import ( + "github.com/a-h/parse" +) + +var doctypeStartParser = parse.StringInsensitive("'. + if _, ok, err = gt.Parse(pi); err != nil || !ok { + err = parse.Error("unclosed DOCTYPE", start) + return + } + + return r, true, nil +}) diff --git a/templ/parser/v2/doctypeparser_test.go b/templ/parser/v2/doctypeparser_test.go new file mode 100644 index 0000000..d9fe9c2 --- /dev/null +++ b/templ/parser/v2/doctypeparser_test.go @@ -0,0 +1,101 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestDocTypeParser(t *testing.T) { + var tests = []struct { + name string + input string + expected DocType + }{ + { + name: "HTML 5 doctype - uppercase", + input: ``, + expected: DocType{ + Value: "html", + }, + }, + { + name: "HTML 5 doctype - lowercase", + input: ``, + expected: DocType{ + Value: "html", + }, + }, + { + name: "HTML 4.01 doctype", + input: ``, + expected: DocType{ + Value: `HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"`, + }, + }, + { + name: "XHTML 1.1", + input: ``, + expected: DocType{ + Value: `html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"`, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := docType.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestDocTypeParserErrors(t *testing.T) { + var tests = []struct { + name string + input string + expected error + }{ + { + name: "doctype unclosed", + input: ``, + expected: parse.Error("unclosed DOCTYPE", + parse.Position{ + Index: 0, + Line: 0, + Col: 0, + }), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + _, _, err := docType.Parse(input) + if diff := cmp.Diff(tt.expected, err); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/parser/v2/elementparser.go b/templ/parser/v2/elementparser.go new file mode 100644 index 0000000..b9ecf4b --- /dev/null +++ b/templ/parser/v2/elementparser.go @@ -0,0 +1,509 @@ +package parser + +import ( + "fmt" + "html" + "strings" + + "github.com/a-h/parse" + "github.com/a-h/templ/parser/v2/goexpression" +) + +// Element. + +// Element open tag. +type elementOpenTag struct { + Name string + Attributes []Attribute + IndentAttrs bool + NameRange Range + Void bool +} + +var elementOpenTagParser = parse.Func(func(pi *parse.Input) (e elementOpenTag, ok bool, err error) { + start := pi.Position() + + // < + if _, ok, err = lt.Parse(pi); err != nil || !ok { + return + } + + // Element name. + l := pi.Position().Line + if e.Name, ok, err = elementNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start.Index) + return + } + e.NameRange = NewRange(pi.PositionAt(pi.Index()-len(e.Name)), pi.Position()) + + if e.Attributes, ok, err = (attributesParser{}).Parse(pi); err != nil || !ok { + pi.Seek(start.Index) + return + } + + // If any attribute is not on the same line as the element name, indent them. + if pi.Position().Line != l { + e.IndentAttrs = true + } + + // Optional whitespace. + if _, _, err = parse.OptionalWhitespace.Parse(pi); err != nil { + pi.Seek(start.Index) + return + } + + // /> + if _, ok, err = parse.String("/>").Parse(pi); err != nil { + return + } + if ok { + e.Void = true + return + } + + // > + if _, ok, err = gt.Parse(pi); err != nil { + return + } + + // If it's not a self-closing or complete open element, we have an error. + if !ok { + err = parse.Error(fmt.Sprintf("<%s>: malformed open element", e.Name), pi.Position()) + return + } + + return e, true, nil +}) + +// Attribute name. +var ( + attributeNameFirst = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_@" + attributeNameSubsequent = attributeNameFirst + "-.0123456789*" + attributeNameParser = parse.Func(func(in *parse.Input) (name string, ok bool, err error) { + start := in.Index() + var prefix, suffix string + if prefix, ok, err = parse.RuneIn(attributeNameFirst).Parse(in); err != nil || !ok { + return + } + if suffix, ok, err = parse.StringUntil(parse.RuneNotIn(attributeNameSubsequent)).Parse(in); err != nil { + in.Seek(start) + return + } + if len(suffix)+1 > 128 { + ok = false + err = parse.Error("attribute names must be < 128 characters long", in.Position()) + return + } + return prefix + suffix, true, nil + }) +) + +type attributeValueParser struct { + EqualsAndQuote parse.Parser[string] + Suffix parse.Parser[string] + UseSingleQuote bool +} + +func (avp attributeValueParser) Parse(pi *parse.Input) (value string, ok bool, err error) { + start := pi.Index() + if _, ok, err = avp.EqualsAndQuote.Parse(pi); err != nil || !ok { + return + } + if value, ok, err = parse.StringUntil(avp.Suffix).Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + if _, ok, err = avp.Suffix.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + return value, true, nil +} + +// Constant attribute. +var ( + attributeValueParsers = []attributeValueParser{ + // Double quoted. + {EqualsAndQuote: parse.String(`="`), Suffix: parse.String(`"`), UseSingleQuote: false}, + // Single quoted. + {EqualsAndQuote: parse.String(`='`), Suffix: parse.String(`'`), UseSingleQuote: true}, + // Unquoted. + // A valid unquoted attribute value in HTML is any string of text that is not an empty string, + // and that doesn’t contain spaces, tabs, line feeds, form feeds, carriage returns, ", ', `, =, <, or >. + {EqualsAndQuote: parse.String("="), Suffix: parse.Any(parse.RuneIn(" \t\n\r\"'`=<>/"), parse.EOF[string]()), UseSingleQuote: false}, + } + constantAttributeParser = parse.Func(func(pi *parse.Input) (attr ConstantAttribute, ok bool, err error) { + start := pi.Index() + + // Optional whitespace leader. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + // Attribute name. + if attr.Name, ok, err = attributeNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + attr.NameRange = NewRange(pi.PositionAt(pi.Index()-len(attr.Name)), pi.Position()) + + for _, p := range attributeValueParsers { + attr.Value, ok, err = p.Parse(pi) + if err != nil { + pos := pi.Position() + if pErr, isParseError := err.(parse.ParseError); isParseError { + pos = pErr.Pos + } + return attr, false, parse.Error(fmt.Sprintf("%s: %v", attr.Name, err), pos) + } + if ok { + attr.SingleQuote = p.UseSingleQuote + break + } + } + + if !ok { + pi.Seek(start) + return attr, false, nil + } + + attr.Value = html.UnescapeString(attr.Value) + + // Only use single quotes if actually required, due to double quote in the value (prefer double quotes). + attr.SingleQuote = attr.SingleQuote && strings.Contains(attr.Value, "\"") + + return attr, true, nil + }) +) + +// BoolConstantAttribute. +var boolConstantAttributeParser = parse.Func(func(pi *parse.Input) (attr BoolConstantAttribute, ok bool, err error) { + start := pi.Index() + + // Optional whitespace leader. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + // Attribute name. + if attr.Name, ok, err = attributeNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + attr.NameRange = NewRange(pi.PositionAt(pi.Index()-len(attr.Name)), pi.Position()) + + // We have a name, but if we have an equals sign, it's not a constant boolean attribute. + next, ok := pi.Peek(1) + if !ok { + err = parse.Error("boolConstantAttributeParser: unexpected EOF after attribute name", pi.Position()) + return + } + if next == "=" || next == "?" { + // It's one of the other attribute types. + pi.Seek(start) + return attr, false, nil + } + if !(next == " " || next == "\t" || next == "\r" || next == "\n" || next == "/" || next == ">") { + err = parse.Error(fmt.Sprintf("boolConstantAttributeParser: expected attribute name to end with space, newline, '/>' or '>', but got %q", next), pi.Position()) + return attr, false, err + } + + return attr, true, nil +}) + +// BoolExpressionAttribute. +var boolExpressionStart = parse.Or(parse.String("?={ "), parse.String("?={")) + +var boolExpressionAttributeParser = parse.Func(func(pi *parse.Input) (r BoolExpressionAttribute, ok bool, err error) { + start := pi.Index() + + // Optional whitespace leader. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + + // Attribute name. + if r.Name, ok, err = attributeNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + r.NameRange = NewRange(pi.PositionAt(pi.Index()-len(r.Name)), pi.Position()) + + // Check whether this is a boolean expression attribute. + if _, ok, err = boolExpressionStart.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + + // Once we have a prefix, we must have an expression that returns a boolean. + if r.Expression, err = parseGo("boolean attribute", pi, goexpression.Expression); err != nil { + return r, false, err + } + + // Eat the Final brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("boolean expression: missing closing brace", pi.Position()) + pi.Seek(start) + return + } + + return r, true, nil +}) + +var expressionAttributeParser = parse.Func(func(pi *parse.Input) (attr ExpressionAttribute, ok bool, err error) { + start := pi.Index() + + // Optional whitespace leader. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + // Attribute name. + if attr.Name, ok, err = attributeNameParser.Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + attr.NameRange = NewRange(pi.PositionAt(pi.Index()-len(attr.Name)), pi.Position()) + + // ={ + if _, ok, err = parse.Or(parse.String("={ "), parse.String("={")).Parse(pi); err != nil || !ok { + pi.Seek(start) + return + } + + // Expression. + if attr.Expression, err = parseGoSliceArgs(pi); err != nil { + return attr, false, err + } + + // Eat whitespace, plus the final brace. + if _, _, err = parse.OptionalWhitespace.Parse(pi); err != nil { + return attr, false, err + } + if _, ok, err = closeBrace.Parse(pi); err != nil || !ok { + err = parse.Error("string expression attribute: missing closing brace", pi.Position()) + return + } + + return attr, true, nil +}) + +var spreadAttributesParser = parse.Func(func(pi *parse.Input) (attr SpreadAttributes, ok bool, err error) { + start := pi.Index() + + // Optional whitespace leader. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + // Eat the first brace. + if _, ok, err = openBraceWithOptionalPadding.Parse(pi); err != nil || + !ok { + pi.Seek(start) + return + } + + // Expression. + if attr.Expression, err = parseGo("spread attributes", pi, goexpression.Expression); err != nil { + return + } + + // Check if end of expression has "..." for spread. + if !strings.HasSuffix(attr.Expression.Value, "...") { + pi.Seek(start) + ok = false + return + } + + // Remove extra spread characters from expression. + attr.Expression.Value = strings.TrimSuffix(attr.Expression.Value, "...") + attr.Expression.Range.To.Col -= 3 + attr.Expression.Range.To.Index -= 3 + + // Eat the final brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("attribute spread expression: missing closing brace", pi.Position()) + return + } + + return attr, true, nil +}) + +// Attributes. +type attributeParser struct{} + +func (attributeParser) Parse(in *parse.Input) (out Attribute, ok bool, err error) { + if out, ok, err = boolExpressionAttributeParser.Parse(in); err != nil || ok { + return + } + if out, ok, err = expressionAttributeParser.Parse(in); err != nil || ok { + return + } + if out, ok, err = conditionalAttribute.Parse(in); err != nil || ok { + return + } + if out, ok, err = boolConstantAttributeParser.Parse(in); err != nil || ok { + return + } + if out, ok, err = spreadAttributesParser.Parse(in); err != nil || ok { + return + } + if out, ok, err = constantAttributeParser.Parse(in); err != nil || ok { + return + } + return +} + +var attribute attributeParser + +type attributesParser struct{} + +func (attributesParser) Parse(in *parse.Input) (attributes []Attribute, ok bool, err error) { + for { + var attr Attribute + attr, ok, err = attribute.Parse(in) + if err != nil { + return + } + if !ok { + break + } + attributes = append(attributes, attr) + } + return attributes, true, nil +} + +// Element name. +var ( + elementNameFirst = "abcdefghijklmnopqrstuvwxyz" + elementNameSubsequent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-:" + elementNameParser = parse.Func(func(in *parse.Input) (name string, ok bool, err error) { + start := in.Index() + var prefix, suffix string + if prefix, ok, err = parse.RuneIn(elementNameFirst).Parse(in); err != nil || !ok { + return + } + if suffix, ok, err = parse.StringUntil(parse.RuneNotIn(elementNameSubsequent)).Parse(in); err != nil || !ok { + in.Seek(start) + return + } + if len(suffix)+1 > 128 { + ok = false + err = parse.Error("element names must be < 128 characters long", in.Position()) + return + } + return prefix + suffix, true, nil + }) +) + +// Void element closer. +var voidElementCloser voidElementCloserParser + +type voidElementCloserParser struct{} + +var voidElementCloseTags = []string{"", "", "
    ", "", "", "", "", "", "", "", "", "", "", "", "", ""} + +func (voidElementCloserParser) Parse(pi *parse.Input) (n Node, ok bool, err error) { + var ve string + for _, ve = range voidElementCloseTags { + s, canPeekLen := pi.Peek(len(ve)) + if !canPeekLen { + continue + } + if !strings.EqualFold(s, ve) { + continue + } + // Found a match. + ok = true + break + } + if !ok { + return nil, false, nil + } + pi.Take(len(ve)) + return nil, true, nil +} + +// Element. +var element elementParser + +type elementParser struct{} + +func (elementParser) Parse(pi *parse.Input) (n Node, ok bool, err error) { + var r Element + start := pi.Position() + + // Check the open tag. + var ot elementOpenTag + if ot, ok, err = elementOpenTagParser.Parse(pi); err != nil || !ok { + return + } + r.Name = ot.Name + r.Attributes = ot.Attributes + r.IndentAttrs = ot.IndentAttrs + r.NameRange = ot.NameRange + + // Once we've got an open tag, the rest must be present. + l := pi.Position().Line + + // If the element is self-closing, even if it's not really a void element (br, hr etc.), we can return early. + if ot.Void || r.IsVoidElement() { + // Escape early, no need to try to parse children for self-closing elements. + return addTrailingSpaceAndValidate(start, r, pi) + } + + // Parse children. + closer := StripType(parse.All(parse.String("'))) + tnp := newTemplateNodeParser(closer, fmt.Sprintf("<%s>: close tag", ot.Name)) + nodes, _, err := tnp.Parse(pi) + if err != nil { + notFoundErr, isNotFoundError := err.(UntilNotFoundError) + if isNotFoundError { + err = notFoundErr.ParseError + } + return r, false, err + } + r.Children = nodes.Nodes + // If the children are not all on the same line, indent them. + if l != pi.Position().Line { + r.IndentChildren = true + } + + // Close tag. + _, ok, err = closer.Parse(pi) + if err != nil { + return r, false, err + } + if !ok { + err = parse.Error(fmt.Sprintf("<%s>: expected end tag not present or invalid tag contents", r.Name), pi.Position()) + return r, false, err + } + + return addTrailingSpaceAndValidate(start, r, pi) +} + +func addTrailingSpaceAndValidate(start parse.Position, e Element, pi *parse.Input) (n Node, ok bool, err error) { + // Elide any void close tags. + if _, _, err = voidElementCloser.Parse(pi); err != nil { + return e, false, err + } + // Add trailing space. + ws, _, err := parse.Whitespace.Parse(pi) + if err != nil { + return e, false, err + } + e.TrailingSpace, err = NewTrailingSpace(ws) + if err != nil { + return e, false, err + } + + // Validate. + var msgs []string + if msgs, ok = e.Validate(); !ok { + err = parse.Error(fmt.Sprintf("<%s>: %s", e.Name, strings.Join(msgs, ", ")), start) + return e, false, err + } + + return e, true, nil +} diff --git a/templ/parser/v2/elementparser_test.go b/templ/parser/v2/elementparser_test.go new file mode 100644 index 0000000..13e37dc --- /dev/null +++ b/templ/parser/v2/elementparser_test.go @@ -0,0 +1,1786 @@ +package parser + +import ( + "strings" + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +type attributeTest[T any] struct { + name string + input string + parser parse.Parser[T] + expected T +} + +func TestAttributeParser(t *testing.T) { + tests := []attributeTest[any]{ + { + name: "element: open", + input: ``, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + }, + }, + { + name: "element: hyphen in name", + input: ``, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "turbo-frame", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + { + name: "element: open with hyperscript attribute", + input: `
    `, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "_", + Value: "show = true", + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + }, + }, + }, + }, + { + name: "element: open with complex attributes", + input: `
    `, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "@click", + Value: "show = true", + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + ConstantAttribute{ + Name: ":class", + Value: "{'foo': true}", + NameRange: Range{ + From: Position{Index: 26, Line: 0, Col: 26}, + To: Position{Index: 32, Line: 0, Col: 32}, + }, + }, + }, + }, + }, + { + name: "element: open with attributes", + input: `
    `, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "id", + Value: "123", + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 7, Line: 0, Col: 7}, + }, + }, + ConstantAttribute{ + Name: "style", + Value: "padding: 10px", + NameRange: Range{ + From: Position{Index: 14, Line: 0, Col: 14}, + To: Position{Index: 19, Line: 0, Col: 19}, + }, + }, + }, + }, + }, + { + name: "conditional expression attribute - single", + input: ` + if p.important { + class="important" + } +"`, + parser: StripType(conditionalAttribute), + expected: ConditionalAttribute{ + Expression: Expression{ + Value: "p.important", + Range: Range{ + From: Position{ + Index: 6, + Line: 1, + Col: 5, + }, + To: Position{ + Index: 17, + Line: 1, + Col: 16, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "important", + NameRange: Range{ + From: Position{Index: 23, Line: 2, Col: 3}, + To: Position{Index: 28, Line: 2, Col: 8}, + }, + }, + }, + }, + }, + { + name: "conditional expression attribute - multiple", + input: ` +if test { + class="itIsTrue" + noshade + name={ "other" } +} +"`, + parser: StripType(conditionalAttribute), + expected: ConditionalAttribute{ + Expression: Expression{ + Value: "test", + Range: Range{ + From: Position{ + Index: 4, + Line: 1, + Col: 3, + }, + To: Position{ + Index: 8, + Line: 1, + Col: 7, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "itIsTrue", + NameRange: Range{ + From: Position{Index: 13, Line: 2, Col: 1}, + To: Position{Index: 18, Line: 2, Col: 6}, + }, + }, + BoolConstantAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 31, Line: 3, Col: 1}, + To: Position{Index: 38, Line: 3, Col: 8}, + }, + }, + ExpressionAttribute{ + Name: "name", + NameRange: Range{ + From: Position{Index: 40, Line: 4, Col: 1}, + To: Position{Index: 44, Line: 4, Col: 5}, + }, + Expression: Expression{ + Value: `"other"`, + Range: Range{ + From: Position{ + Index: 47, + Line: 4, + Col: 8, + }, + To: Position{ + Index: 54, + Line: 4, + Col: 15, + }, + }, + }, + }, + }, + }, + }, + { + name: "boolean expression attribute", + input: ` noshade?={ true }"`, + parser: StripType(boolExpressionAttributeParser), + expected: BoolExpressionAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + { + name: "boolean expression attribute without spaces", + input: ` noshade?={true}"`, + parser: StripType(boolExpressionAttributeParser), + expected: BoolExpressionAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + To: Position{ + Index: 15, + Line: 0, + Col: 15, + }, + }, + }, + }, + }, + { + name: "attribute parsing handles boolean expression attributes", + input: ` noshade?={ true }`, + parser: StripType(attributeParser{}), + expected: BoolExpressionAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + { + name: "boolean expression with excess spaces", + input: ` noshade?={ true }"`, + parser: StripType(boolExpressionAttributeParser), + expected: BoolExpressionAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + { + name: "spread attributes", + input: ` { spread... }"`, + parser: StripType(spreadAttributesParser), + expected: SpreadAttributes{ + Expression{ + Value: "spread", + Range: Range{ + From: Position{ + Index: 3, + Line: 0, + Col: 3, + }, + To: Position{ + Index: 9, + Line: 0, + Col: 9, + }, + }, + }, + }, + }, + { + name: "constant attribute", + input: ` href="test"`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "href", + Value: "test", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + { + name: "single quote not required constant attribute", + input: ` href='no double quote in value'`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "href", + Value: `no double quote in value`, + SingleQuote: false, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + { + name: "single quote required constant attribute", + input: ` href='"test"'`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "href", + Value: `"test"`, + SingleQuote: true, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + { + name: "attribute name with hyphens", + input: ` data-turbo-permanent="value"`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "data-turbo-permanent", + Value: "value", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 21, Line: 0, Col: 21}, + }, + }, + }, + { + name: "empty attribute", + input: ` data=""`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "data", + Value: "", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + { + name: "multiline attribute", + input: ` data-script="on click + do something + end" +`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "data-script", + Value: "on click\n do something\n end", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + { + name: "bool constant attribute", + input: `
    `, + parser: StripType(elementOpenTagParser), + expected: elementOpenTag{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Attributes: []Attribute{ + BoolConstantAttribute{ + Name: "data", + + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + }, + }, + }, + { + name: "bool constant attributes can end with a Unix newline", + input: "", + parser: StripType(element), + expected: Element{ + Name: "input", + IndentAttrs: true, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + Attributes: []Attribute{ + BoolConstantAttribute{ + Name: "required", + NameRange: Range{ + From: Position{Index: 9, Line: 1, Col: 2}, + To: Position{Index: 17, Line: 1, Col: 10}, + }, + }, + }, + }, + }, + { + name: "bool constant attributes can end with a Windows newline", + input: "", + parser: StripType(element), + expected: Element{ + Name: "input", + IndentAttrs: true, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + Attributes: []Attribute{ + BoolConstantAttribute{ + Name: "required", + NameRange: Range{ + From: Position{Index: 10, Line: 1, Col: 2}, + To: Position{Index: 18, Line: 1, Col: 10}, + }, + }, + }, + }, + }, + { + name: "attribute containing escaped text", + input: ` href="<">"`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "href", + Value: `<">`, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + { + name: "HTMX wildcard attribute names are supported", + input: ` hx-target-*="#errors"`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "hx-target-*", + Value: `#errors`, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + { + name: "unquoted attributes are supported", + input: ` data=123`, + parser: StripType(constantAttributeParser), + expected: ConstantAttribute{ + Name: "data", + Value: "123", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := tt.parser.Parse(input) + if err != nil { + t.Error(err) + } + if !ok { + t.Errorf("failed to parse at %v", input.Position()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestVoidElementCloserParser(t *testing.T) { + t.Run("all void elements are parsed", func(t *testing.T) { + for _, input := range voidElementCloseTags { + _, ok, err := voidElementCloser.Parse(parse.NewInput(input)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("failed to parse %q", input) + } + } + }) +} + +func TestElementParser(t *testing.T) { + tests := []struct { + name string + input string + expected Element + }{ + { + name: "element: self-closing with single constant attribute", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "href", + Value: "test", + NameRange: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 7, Line: 0, Col: 7}, + }, + }, + }, + }, + }, + { + name: "element: colon in name, empty", + input: ``, + expected: Element{ + Name: "maps:map", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + }, + { + name: "element: colon in name, with content", + input: `Content`, + expected: Element{ + Name: "maps:map", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + Children: []Node{ + Text{ + Value: "Content", + Range: Range{ + From: Position{Index: 10, Line: 0, Col: 10}, + To: Position{Index: 17, Line: 0, Col: 17}, + }, + }, + }, + }, + }, + { + name: "element: void (input)", + input: ``, + expected: Element{ + Name: "input", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + Children: nil, + }, + }, + { + name: "element: void (br)", + input: `
    `, + expected: Element{ + Name: "br", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Children: nil, + }, + }, + { + name: "element: void (hr)", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + BoolConstantAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + }, + Children: nil, + }, + }, + { + name: "element: void with content", + input: `Text`, + expected: Element{ + Name: "input", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + // is a void element, so text is not a child of the input. + // is ignored. + Children: nil, + }, + }, + { + name: "element: self-closing with single bool expression attribute", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + BoolExpressionAttribute{ + Name: "noshade", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + Expression: Expression{ + Value: `true`, + Range: Range{ + From: Position{ + Index: 15, + Line: 0, + Col: 15, + }, + To: Position{ + Index: 19, + Line: 0, + Col: 19, + }, + }, + }, + }, + }, + }, + }, + { + name: "element: void nesting same is OK", + input: `



    `, + expected: Element{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Children: []Node{ + Element{ + Name: "br", // The
    one. + NameRange: Range{ + From: Position{Index: 6, Line: 0, Col: 6}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + }, + Element{ + Name: "br", // The

    one. + NameRange: Range{ + From: Position{Index: 10, Line: 0, Col: 10}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + }, + }, + { + name: "element: void nesting is ignored", + input: `


    `, + expected: Element{ + Name: "br", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + //
    is a void element, so
    is not a child of the
    . + //
    is ignored. + Children: nil, + }, + }, + { + name: "element: self-closing with single expression attribute", + input: `
    `, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + ExpressionAttribute{ + Name: "href", + NameRange: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 7, Line: 0, Col: 7}, + }, + Expression: Expression{ + Value: `"test"`, + Range: Range{ + From: Position{ + Index: 10, + Line: 0, + Col: 10, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + }, + }, + { + name: "element: self-closing with multiple constant attributes", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "href", + Value: "test", + NameRange: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 7, Line: 0, Col: 7}, + }, + }, + ConstantAttribute{ + Name: "style", + Value: "text-underline: auto", + NameRange: Range{ + From: Position{Index: 15, Line: 0, Col: 15}, + To: Position{Index: 20, Line: 0, Col: 20}, + }, + }, + }, + }, + }, + { + name: "element: self-closing with multiple spreads attributes", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + SpreadAttributes{ + Expression: Expression{ + Value: "firstSpread", + Range: Range{ + From: Position{ + Index: 5, + Line: 0, + Col: 5, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + SpreadAttributes{ + Expression: Expression{ + Value: "children", + Range: Range{ + From: Position{ + Index: 24, + Line: 0, + Col: 24, + }, + To: Position{ + Index: 32, + Line: 0, + Col: 32, + }, + }, + }, + }, + }, + }, + }, + { + name: "element: self-closing with multiple boolean attributes", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + BoolConstantAttribute{ + Name: "optionA", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + BoolExpressionAttribute{ + Name: "optionB", + NameRange: Range{ + From: Position{Index: 12, Line: 0, Col: 12}, + To: Position{Index: 19, Line: 0, Col: 19}, + }, + Expression: Expression{ + Value: `true`, + Range: Range{ + From: Position{ + Index: 23, + Line: 0, + Col: 23, + }, + To: Position{ + Index: 27, + Line: 0, + Col: 27, + }, + }, + }, + }, + ConstantAttribute{ + Name: "optionC", + Value: "other", + NameRange: Range{ + From: Position{Index: 30, Line: 0, Col: 30}, + To: Position{Index: 37, Line: 0, Col: 37}, + }, + }, + }, + }, + }, + { + name: "element: self-closing with multiple constant and expr attributes", + input: `
    `, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "href", + Value: "test", + NameRange: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 7, Line: 0, Col: 7}, + }, + }, + ExpressionAttribute{ + Name: "title", + NameRange: Range{ + From: Position{Index: 15, Line: 0, Col: 15}, + To: Position{Index: 20, Line: 0, Col: 20}, + }, + Expression: Expression{ + Value: `localisation.Get("a_title")`, + Range: Range{ + From: Position{ + Index: 23, + Line: 0, + Col: 23, + }, + To: Position{ + Index: 50, + Line: 0, + Col: 50, + }, + }, + }, + }, + ConstantAttribute{ + Name: "style", + Value: "text-underline: auto", + NameRange: Range{ + From: Position{Index: 53, Line: 0, Col: 53}, + To: Position{Index: 58, Line: 0, Col: 58}, + }, + }, + }, + }, + }, + { + name: "element: self-closing with multiple constant, conditional and expr attributes", + input: `
    Test
    +} + +`, + expected: Element{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "style", + Value: "width: 100;", + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 10, Line: 0, Col: 10}, + }, + }, + ConditionalAttribute{ + Expression: Expression{ + Value: `p.important`, + Range: Range{ + From: Position{ + Index: 30, + Line: 1, + Col: 5, + }, + To: Position{ + Index: 41, + Line: 1, + Col: 16, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "important", + NameRange: Range{ + From: Position{Index: 47, Line: 2, Col: 3}, + To: Position{Index: 52, Line: 2, Col: 8}, + }, + }, + }, + }, + }, + IndentAttrs: true, + Children: []Node{ + Text{ + Value: "Test", + Range: Range{ + From: Position{Index: 70, Line: 4, Col: 1}, + To: Position{Index: 74, Line: 4, Col: 5}, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + { + name: "element: self-closing with no attributes", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + }, + }, + { + name: "element: self-closing with attribute", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "style", + Value: "padding: 10px", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + }, + }, + }, + { + name: "element: self-closing with conditional attribute", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "style", + Value: "padding: 10px", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + ConditionalAttribute{ + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 33, + Line: 1, + Col: 6, + }, + To: Position{ + Index: 37, + Line: 1, + Col: 10, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "itIsTrue", + NameRange: Range{ + From: Position{Index: 44, Line: 2, Col: 4}, + To: Position{Index: 49, Line: 2, Col: 9}, + }, + }, + }, + }, + }, + IndentAttrs: true, + }, + }, + { + name: "element: self-closing with conditional attribute with else block", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "style", + Value: "padding: 10px", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + ConditionalAttribute{ + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 33, + Line: 1, + Col: 6, + }, + To: Position{ + Index: 37, + Line: 1, + Col: 10, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "itIsTrue", + NameRange: Range{ + From: Position{Index: 44, Line: 2, Col: 4}, + To: Position{Index: 49, Line: 2, Col: 9}, + }, + }, + }, + Else: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "itIsNotTrue", + NameRange: Range{ + From: Position{Index: 77, Line: 4, Col: 4}, + To: Position{Index: 82, Line: 4, Col: 9}, + }, + }, + }, + }, + }, + IndentAttrs: true, + }, + }, + { + name: "element: open and close with conditional attribute", + input: `

    Test

    `, + expected: Element{ + Name: "p", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "style", + Value: "padding: 10px", + NameRange: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 8, Line: 0, Col: 8}, + }, + }, + ConditionalAttribute{ + Expression: Expression{ + Value: "true", + Range: Range{ + From: Position{ + Index: 32, + Line: 1, + Col: 6, + }, + To: Position{ + Index: 36, + Line: 1, + Col: 10, + }, + }, + }, + Then: []Attribute{ + ConstantAttribute{ + Name: "class", + Value: "itIsTrue", + NameRange: Range{ + From: Position{Index: 43, Line: 2, Col: 4}, + To: Position{Index: 48, Line: 2, Col: 9}, + }, + }, + }, + }, + }, + IndentAttrs: true, + Children: []Node{ + Text{ + Value: "Test", + Range: Range{ + From: Position{Index: 66, Line: 4, Col: 1}, + To: Position{Index: 70, Line: 4, Col: 5}, + }, + }, + }, + }, + }, + { + name: "element: open and close", + input: `
    `, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + }, + }, + { + name: "element: open and close with text", + input: `The text`, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Children: []Node{ + Text{ + Value: "The text", + Range: Range{ + From: Position{Index: 3, Line: 0, Col: 3}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + }, + }, + }, + { + name: "element: with self-closing child element", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Children: []Node{ + Element{ + Name: "b", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + }, + }, + { + name: "element: with non-self-closing child element", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Children: []Node{ + Element{ + Name: "b", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + }, + }, + }, + { + name: "element: containing space", + input: ` `, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Children: []Node{ + Whitespace{Value: " "}, + Element{ + Name: "b", + NameRange: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + + Children: []Node{ + Whitespace{Value: " "}, + }, + TrailingSpace: SpaceHorizontal, + }, + }, + }, + }, + { + name: "element: with multiple child elements", + input: ``, + expected: Element{ + Name: "a", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 2, Line: 0, Col: 2}, + }, + Children: []Node{ + Element{ + Name: "b", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 5, Line: 0, Col: 5}, + }, + }, + Element{ + Name: "c", + NameRange: Range{ + From: Position{Index: 11, Line: 0, Col: 11}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + Children: []Node{ + Element{ + Name: "d", + NameRange: Range{ + From: Position{Index: 14, Line: 0, Col: 14}, + To: Position{Index: 15, Line: 0, Col: 15}, + }, + }, + }, + }, + }, + }, + }, + { + name: "element: empty", + input: `
    `, + expected: Element{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + }, + }, + { + name: "element: containing string expression", + input: `
    { "test" }
    `, + expected: Element{ + Name: "div", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Children: []Node{ + StringExpression{ + Expression: Expression{ + Value: `"test"`, + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 13, + Line: 0, + Col: 13, + }, + }, + }, + }, + }, + }, + }, + { + name: "element: inputs can contain class attributes", + input: ``, + expected: Element{ + Name: "input", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "type", + Value: "email", + NameRange: Range{ + From: Position{Index: 8, Line: 0, Col: 8}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + ConstantAttribute{ + Name: "id", + Value: "email", + NameRange: Range{ + From: Position{Index: 21, Line: 0, Col: 21}, + To: Position{Index: 23, Line: 0, Col: 23}, + }, + }, + ConstantAttribute{ + Name: "name", + Value: "email", + NameRange: Range{ + From: Position{Index: 32, Line: 0, Col: 32}, + To: Position{Index: 36, Line: 0, Col: 36}, + }, + }, + ExpressionAttribute{ + Name: "class", + NameRange: Range{ + From: Position{Index: 45, Line: 0, Col: 45}, + To: Position{Index: 50, Line: 0, Col: 50}, + }, + Expression: Expression{ + Value: `"a", "b", "c", templ.KV("c", false)`, + Range: Range{ + From: Position{ + Index: 53, + Line: 0, + Col: 53, + }, + To: Position{ + Index: 89, + Line: 0, + Col: 89, + }, + }, + }, + }, + ConstantAttribute{ + Name: "placeholder", + Value: "your@email.com", + NameRange: Range{ + From: Position{Index: 91, Line: 0, Col: 91}, + To: Position{Index: 102, Line: 0, Col: 102}, + }, + }, + ConstantAttribute{ + Name: "autocomplete", + Value: "off", + NameRange: Range{ + From: Position{Index: 120, Line: 0, Col: 120}, + To: Position{Index: 132, Line: 0, Col: 132}, + }, + }, + }, + }, + }, + { + name: "element: with multi-line attributes", + input: ``, + expected: Element{ + Name: "input", + IndentAttrs: true, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "type", + Value: "email", + NameRange: Range{ + From: Position{Index: 8, Line: 1, Col: 1}, + To: Position{Index: 12, Line: 1, Col: 5}, + }, + }, + ConstantAttribute{ + Name: "id", + Value: "email", + NameRange: Range{ + From: Position{Index: 23, Line: 2, Col: 1}, + To: Position{Index: 25, Line: 2, Col: 3}, + }, + }, + ConstantAttribute{ + Name: "name", + Value: "email", + NameRange: Range{ + From: Position{Index: 36, Line: 3, Col: 1}, + To: Position{Index: 40, Line: 3, Col: 5}, + }, + }, + }, + }, + }, + { + name: "element: can contain text that starts with for", + input: `
    for which any +amount is charged
    `, + expected: Element{ + Name: "div", + IndentChildren: true, + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 4, Line: 0, Col: 4}, + }, + Children: []Node{ + Text{ + Value: "for which any ", + Range: Range{ + From: Position{Index: 5, Line: 0, Col: 5}, + To: Position{Index: 19, Line: 0, Col: 19}, + }, + TrailingSpace: SpaceVertical, + }, + Text{ + Value: "amount is charged", + Range: Range{ + From: Position{Index: 20, Line: 1, Col: 0}, + To: Position{Index: 37, Line: 1, Col: 17}, + }, + TrailingSpace: SpaceNone, + }, + }, + }, + }, + { + name: "element: self-closing with unquoted attribute", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "noshade", + Value: "noshade", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + }, + }, + }, + { + name: "element: self-closing with unquoted and other attributes", + input: `
    `, + expected: Element{ + Name: "hr", + NameRange: Range{ + From: Position{Index: 1, Line: 0, Col: 1}, + To: Position{Index: 3, Line: 0, Col: 3}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "noshade", + Value: "noshade", + NameRange: Range{ + From: Position{Index: 4, Line: 0, Col: 4}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + BoolConstantAttribute{ + Name: "disabled", + NameRange: Range{ + From: Position{Index: 20, Line: 0, Col: 20}, + To: Position{Index: 28, Line: 0, Col: 28}, + }, + }, + ExpressionAttribute{ + Name: "other-attribute", + NameRange: Range{ + From: Position{Index: 29, Line: 0, Col: 29}, + To: Position{Index: 44, Line: 0, Col: 44}, + }, + Expression: Expression{ + Value: "false", + Range: Range{ + From: Position{ + Index: 47, + Line: 0, + Col: 47, + }, + To: Position{ + Index: 52, + Line: 0, + Col: 52, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + result, ok, err := element.Parse(input) + if err != nil { + t.Fatalf("parser error: %v", err) + } + if !ok { + t.Fatalf("failed to parse at %d", input.Index()) + } + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestElementParserErrors(t *testing.T) { + tests := []struct { + name string + input string + expected error + }{ + { + name: "element: mismatched end tag", + input: `
    `, + expected: parse.Error(": close tag not found", + parse.Position{ + Index: 3, + Line: 0, + Col: 3, + }), + }, + { + name: "element: style must only contain text", + input: ``, + expected: parse.Error("`, + expected: parse.Error("`, + expected: RawElement{ + Name: "style", + Attributes: []Attribute{ + ConstantAttribute{ + Name: "type", + Value: "text/css", + NameRange: Range{ + From: Position{Index: 7, Line: 0, Col: 7}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + }, + Contents: "contents", + }, + }, + { + name: "style tag containing mismatched braces", + input: `", + expected: RawElement{ + Name: "style", + Attributes: []Attribute{ + ConstantAttribute{ + Name: "type", + Value: "text/css", + NameRange: Range{ + From: Position{Index: 7, Line: 0, Col: 7}, + To: Position{Index: 11, Line: 0, Col: 11}, + }, + }, + }, + Contents: ignoredContent, + }, + }, + { + name: "script tag", + input: ``, + expected: RawElement{ + Name: "script", + Attributes: []Attribute{ + ConstantAttribute{ + Name: "type", + Value: "vbscript", + NameRange: Range{ + From: Position{Index: 8, Line: 0, Col: 8}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + Contents: "dim x = 1", + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := rawElements.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestRawElementParserIsNotGreedy(t *testing.T) { + var tests = []struct { + name string + input string + expected RawElement + }{ + { + name: "styles tag", + input: ``, + }, + { + name: "scripts tag", + input: ``, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := rawElements.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { + t.Fatalf("unexpected success for input %q", tt.input) + } + if actual != nil { + t.Fatalf("expected nil Node got %v", actual) + } + }) + } +} diff --git a/templ/parser/v2/scripttemplateparser.go b/templ/parser/v2/scripttemplateparser.go new file mode 100644 index 0000000..0770baf --- /dev/null +++ b/templ/parser/v2/scripttemplateparser.go @@ -0,0 +1,88 @@ +package parser + +import ( + "github.com/a-h/parse" +) + +var scriptTemplateParser = parse.Func(func(pi *parse.Input) (r ScriptTemplate, ok bool, err error) { + start := pi.Position() + + // Parse the name. + var se scriptExpression + if se, ok, err = scriptExpressionParser.Parse(pi); err != nil || !ok { + pi.Seek(start.Index) + return + } + r.Name = se.Name + r.Parameters = se.Parameters + + // Read code expression. + var e Expression + if e, ok, err = exp.Parse(pi); err != nil || !ok { + pi.Seek(start.Index) + return + } + r.Value = e.Value + + // Try for } + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("script template: missing closing brace", pi.Position()) + return + } + + r.Range = NewRange(start, pi.Position()) + + return r, true, nil +}) + +// script Func() { +type scriptExpression struct { + Name Expression + Parameters Expression +} + +var scriptExpressionNameParser = ExpressionOf(parse.StringFrom( + parse.Letter, + parse.StringFrom(parse.AtMost(1000, parse.Any(parse.Letter, parse.ZeroToNine))), +)) + +var scriptExpressionParser = parse.Func(func(pi *parse.Input) (r scriptExpression, ok bool, err error) { + // Check the prefix first. + if _, ok, err = parse.String("script ").Parse(pi); err != nil || !ok { + return + } + + // Once we have the prefix, we must have a name and parameters. + // Read the name of the function. + if r.Name, ok, err = scriptExpressionNameParser.Parse(pi); err != nil || !ok { + err = parse.Error("script expression: invalid name", pi.Position()) + return + } + + // Eat the open bracket. + if _, ok, err = openBracket.Parse(pi); err != nil || !ok { + err = parse.Error("script expression: parameters missing open bracket", pi.Position()) + return + } + + // Read the parameters. + // p Person, other Other, t thing.Thing) + if r.Parameters, ok, err = ExpressionOf(parse.StringUntil(closeBracket)).Parse(pi); err != nil || !ok { + err = parse.Error("script expression: parameters missing close bracket", pi.Position()) + return + } + + // Eat ") {". + if _, ok, err = expressionFuncEnd.Parse(pi); err != nil || !ok { + err = parse.Error("script expression: unterminated (missing ') {')", pi.Position()) + return + } + + // Expect a newline. + if _, ok, err = parse.NewLine.Parse(pi); err != nil || !ok { + err = parse.Error("script expression: missing terminating newline", pi.Position()) + return + } + + return r, true, nil +}) diff --git a/templ/parser/v2/scripttemplateparser_test.go b/templ/parser/v2/scripttemplateparser_test.go new file mode 100644 index 0000000..d400eaf --- /dev/null +++ b/templ/parser/v2/scripttemplateparser_test.go @@ -0,0 +1,296 @@ +package parser + +import ( + "fmt" + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestScriptTemplateParser(t *testing.T) { + var tests = []struct { + name string + input string + expected ScriptTemplate + }{ + { + name: "script: no parameters, no content", + input: `script Name() { +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 17, Line: 1, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Parameters: Expression{ + Value: "", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + }, + }, + }, + }, + { + name: "script: no spaces", + input: `script Name(){ +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 16, Line: 1, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Parameters: Expression{ + Value: "", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + }, + }, + }, + }, + { + name: "script: containing a JS variable", + input: `script Name() { +var x = "x"; +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 30, Line: 2, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Parameters: Expression{ + Value: "", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + }, + }, + Value: `var x = "x";` + "\n", + }, + }, + { + name: "script: single argument", + input: `script Name(value string) { +console.log(value); +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 49, Line: 2, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Parameters: Expression{ + Value: "value string", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 24, + Line: 0, + Col: 24, + }, + }, + }, + Value: `console.log(value);` + "\n", + }, + }, + { + name: "script: comment with single quote", + input: `script Name() { + //' +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 22, Line: 2, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Parameters: Expression{ + Value: "", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + }, + }, + Value: ` //'` + "\n", + }, + }, + { + name: "script: empty assignment", + input: `script Name() { + let x = ''; +}`, + expected: ScriptTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 31, Line: 2, Col: 1}, + }, + Name: Expression{ + Value: "Name", + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 11, + Line: 0, + Col: 11, + }, + }, + }, + Value: ` let x = '';` + "\n", + Parameters: Expression{ + Value: "", + Range: Range{ + From: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + To: Position{ + Index: 12, + Line: 0, + Col: 12, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + suffixes := []string{"", " Trailing '", ` Trailing "`, "\n// More content."} + for i, suffix := range suffixes { + t.Run(fmt.Sprintf("%s_%d", tt.name, i), func(t *testing.T) { + input := parse.NewInput(tt.input + suffix) + actual, ok, err := scriptTemplateParser.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + actualSuffix, _ := input.Peek(-1) + if diff := cmp.Diff(suffix, actualSuffix); diff != "" { + t.Error("unexpected suffix") + t.Error(diff) + } + }) + } + } +} diff --git a/templ/parser/v2/sourcemap.go b/templ/parser/v2/sourcemap.go new file mode 100644 index 0000000..ef259cc --- /dev/null +++ b/templ/parser/v2/sourcemap.go @@ -0,0 +1,134 @@ +package parser + +import ( + "strings" + "unicode/utf8" +) + +// NewSourceMap creates a new lookup to map templ source code to items in the +// parsed template. +func NewSourceMap() *SourceMap { + return &SourceMap{ + SourceLinesToTarget: make(map[uint32]map[uint32]Position), + TargetLinesToSource: make(map[uint32]map[uint32]Position), + SourceSymbolRangeToTarget: make(map[uint32]map[uint32]Range), + TargetSymbolRangeToSource: make(map[uint32]map[uint32]Range), + } +} + +type SourceMap struct { + Expressions []string + SourceLinesToTarget map[uint32]map[uint32]Position + TargetLinesToSource map[uint32]map[uint32]Position + SourceSymbolRangeToTarget map[uint32]map[uint32]Range + TargetSymbolRangeToSource map[uint32]map[uint32]Range +} + +func (sm *SourceMap) AddSymbolRange(src Range, tgt Range) { + sm.SourceSymbolRangeToTarget[src.From.Line] = make(map[uint32]Range) + sm.SourceSymbolRangeToTarget[src.From.Line][src.From.Col] = tgt + sm.TargetSymbolRangeToSource[tgt.From.Line] = make(map[uint32]Range) + sm.TargetSymbolRangeToSource[tgt.From.Line][tgt.From.Col] = src +} + +func (sm *SourceMap) SymbolTargetRangeFromSource(line, col uint32) (tgt Range, ok bool) { + lm, ok := sm.SourceSymbolRangeToTarget[line] + if !ok { + return + } + tgt, ok = lm[col] + return +} + +func (sm *SourceMap) SymbolSourceRangeFromTarget(line, col uint32) (src Range, ok bool) { + lm, ok := sm.TargetSymbolRangeToSource[line] + if !ok { + return + } + src, ok = lm[col] + return +} + +// Add an item to the lookup. +func (sm *SourceMap) Add(src Expression, tgt Range) (updatedFrom Position) { + sm.Expressions = append(sm.Expressions, src.Value) + srcIndex := src.Range.From.Index + tgtIndex := tgt.From.Index + + lines := strings.Split(src.Value, "\n") + for lineIndex, line := range lines { + srcLine := src.Range.From.Line + uint32(lineIndex) + tgtLine := tgt.From.Line + uint32(lineIndex) + + var srcCol, tgtCol uint32 + if lineIndex == 0 { + // First line can have an offset. + srcCol += src.Range.From.Col + tgtCol += tgt.From.Col + } + + // Process the cols. + for _, r := range line { + if _, ok := sm.SourceLinesToTarget[srcLine]; !ok { + sm.SourceLinesToTarget[srcLine] = make(map[uint32]Position) + } + sm.SourceLinesToTarget[srcLine][srcCol] = NewPosition(tgtIndex, tgtLine, tgtCol) + + if _, ok := sm.TargetLinesToSource[tgtLine]; !ok { + sm.TargetLinesToSource[tgtLine] = make(map[uint32]Position) + } + sm.TargetLinesToSource[tgtLine][tgtCol] = NewPosition(srcIndex, srcLine, srcCol) + + // Ignore invalid runes. + rlen := utf8.RuneLen(r) + if rlen < 0 { + rlen = 1 + } + srcCol += uint32(rlen) + tgtCol += uint32(rlen) + srcIndex += int64(rlen) + tgtIndex += int64(rlen) + } + + // LSPs include the newline char as a col. + if _, ok := sm.SourceLinesToTarget[srcLine]; !ok { + sm.SourceLinesToTarget[srcLine] = make(map[uint32]Position) + } + sm.SourceLinesToTarget[srcLine][srcCol] = NewPosition(tgtIndex, tgtLine, tgtCol) + + if _, ok := sm.TargetLinesToSource[tgtLine]; !ok { + sm.TargetLinesToSource[tgtLine] = make(map[uint32]Position) + } + sm.TargetLinesToSource[tgtLine][tgtCol] = NewPosition(srcIndex, srcLine, srcCol) + + srcIndex++ + tgtIndex++ + } + return src.Range.From +} + +// TargetPositionFromSource looks up the target position using the source position. +func (sm *SourceMap) TargetPositionFromSource(line, col uint32) (tgt Position, ok bool) { + lm, ok := sm.SourceLinesToTarget[line] + if !ok { + return + } + tgt, ok = lm[col] + return +} + +// SourcePositionFromTarget looks the source position using the target position. +// If a source exists on the line but not the col, the function will search backwards. +func (sm *SourceMap) SourcePositionFromTarget(line, col uint32) (src Position, ok bool) { + lm, ok := sm.TargetLinesToSource[line] + if !ok { + return + } + for { + src, ok = lm[col] + if ok || col == 0 { + return + } + col-- + } +} diff --git a/templ/parser/v2/sourcemap_test.go b/templ/parser/v2/sourcemap_test.go new file mode 100644 index 0000000..362f06f --- /dev/null +++ b/templ/parser/v2/sourcemap_test.go @@ -0,0 +1,174 @@ +package parser + +import ( + "sort" + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +// Test data. +// +// | - | 0 1 2 3 4 5 6 7 8 9 +// | - | - - - - - - - - - +// | 0 | +// | 1 | a b c d e f g h i +// | 2 | j k l m n o +// | 3 | p q r s t u v +// | 4 | +// | 5 | w x y +// | 6 | z +// | 7 | m u l t i +// | 8 | l i n e +// | 9 | m a t c h +// | 10 | 生 日 快 乐 +func pos(index, line, col int) parse.Position { + return parse.Position{ + Index: index, + Line: line, + Col: col, + } +} + +func TestSourceMapPosition(t *testing.T) { + sm := NewSourceMap() + + // Test that out of bounds requests don't return results. + t.Run("out of bounds", func(t *testing.T) { + actualTarget, ok := sm.TargetPositionFromSource(20, 10) + if ok { + t.Errorf("searching for a source position that's not in the map should not result in a target position, but got %v", actualTarget) + } + actualSource, ok := sm.SourcePositionFromTarget(20, 10) + if ok { + t.Errorf("searching for a target position that's not in the map should not result in a source position, but got %v", actualSource) + } + }) + + var tests = []struct { + name string + setup func(sm *SourceMap) + source Position + target Position + expectedOK bool + }{ + { + name: "searching within the map returns a result", + setup: func(sm *SourceMap) { + sm.Add(NewExpression("abc", pos(0, 1, 1), pos(2, 1, 3)), + Range{From: NewPosition(0, 5, 1), To: NewPosition(0, 5, 3)}) + }, + source: NewPosition(0, 1, 1), // a + target: NewPosition(0, 5, 1), + }, + { + name: "offsets within the match are handled", + setup: func(sm *SourceMap) { + sm.Add(NewExpression("abc", pos(0, 1, 1), pos(2, 1, 3)), + Range{From: NewPosition(0, 5, 1), To: NewPosition(0, 5, 3)}) + }, + source: NewPosition(1, 1, 2), // b + target: NewPosition(1, 5, 2), + }, + { + name: "the match that starts closest to the source is returned", + setup: func(sm *SourceMap) { + sm.Add(NewExpression("rst", pos(4, 3, 3), pos(7, 3, 6)), + Range{From: NewPosition(0, 8, 6), To: NewPosition(0, 8, 9)}) + // s is inside rst. + sm.Add(NewExpression("s", pos(-1, 3, 4), pos(-1, 3, 4)), + Range{From: NewPosition(-1, 8, 7), To: NewPosition(-1, 8, 7)}) + }, + source: NewPosition(-1, 3, 4), // s + target: NewPosition(-1, 8, 7), + }, + { + name: "the start line within a multiline match is detected", + setup: func(sm *SourceMap) { + // Multi-line match. + sm.Add(NewExpression("multi\nline\nmatch", pos(0, 0, 0), pos(16, 2, 5)), + Range{From: NewPosition(1, 1, 1), To: NewPosition(17, 3, 5)}) + }, + source: NewPosition(0, 0, 0), // m (ulti) + target: NewPosition(1, 1, 1), + }, + { + name: "the middle line within a multiline match is detected", + setup: func(sm *SourceMap) { + // Multi-line match. + sm.Add(NewExpression("multi\nline\nmatch", pos(0, 0, 0), pos(16, 2, 5)), + Range{From: NewPosition(1, 1, 1), To: NewPosition(17, 3, 5)}) + }, + source: NewPosition(7, 1, 1), // (l) i (ne) + target: NewPosition(8, 2, 1), + }, + { + name: "the final line within a multiline match is detected", + setup: func(sm *SourceMap) { + // Multi-line match. + sm.Add(NewExpression("multi\nline\nmatch", pos(0, 0, 0), pos(16, 2, 5)), + Range{From: NewPosition(1, 1, 1), To: NewPosition(17, 3, 5)}) + }, + source: NewPosition(11, 2, 0), // m (atch) + target: NewPosition(12, 3, 0), + }, + { + name: "unicode characters are indexed correctly (sheng)", + setup: func(sm *SourceMap) { + sm.Add(NewExpression("生日快乐", pos(0, 10, 0), pos(12, 10, 4)), + Range{From: NewPosition(1, 11, 1), To: NewPosition(13, 11, 5)}) + }, + source: NewPosition(0, 10, 0), // 生 + target: NewPosition(1, 11, 1), + }, + { + name: "unicode characters are indexed correctly (ri)", + setup: func(sm *SourceMap) { + sm.Add(NewExpression("生日快乐", pos(0, 10, 0), pos(12, 10, 4)), + Range{From: NewPosition(1, 11, 1), To: NewPosition(13, 11, 5)}) + }, + source: NewPosition(3, 10, 3), // 日 + target: NewPosition(4, 11, 4), + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + sm := NewSourceMap() + tt.setup(sm) + actualTarget, ok := sm.TargetPositionFromSource(uint32(tt.source.Line), uint32(tt.source.Col)) + if !ok { + t.Errorf("TargetPositionFromSource: expected result from source %v, got no results", tt.source) + } + if diff := cmp.Diff(tt.target, actualTarget); diff != "" { + lines := keys(sm.SourceLinesToTarget) + sort.Slice(lines, func(i, j int) bool { + return lines[i] < lines[j] + }) + for _, lineIndex := range lines { + cols := keys(sm.SourceLinesToTarget[lineIndex]) + sort.Slice(cols, func(i, j int) bool { + return cols[i] < cols[j] + }) + t.Error(lineIndex, cols) + } + t.Error("TargetPositionFromSource\n\n" + diff) + } + actualSource, ok := sm.SourcePositionFromTarget(actualTarget.Line, actualTarget.Col) + if !ok { + t.Fatalf("SourcePositionFromTarget: expected result, got no results") + } + if diff := cmp.Diff(tt.source, actualSource); diff != "" { + t.Error("SourcePositionFromTarget\n\n" + diff) + } + }) + } +} + +func keys[K comparable, V any](m map[K]V) (keys []K) { + for k := range m { + keys = append(keys, k) + } + return +} diff --git a/templ/parser/v2/stringexpressionparser.go b/templ/parser/v2/stringexpressionparser.go new file mode 100644 index 0000000..0a44571 --- /dev/null +++ b/templ/parser/v2/stringexpressionparser.go @@ -0,0 +1,39 @@ +package parser + +import ( + "github.com/a-h/parse" +) + +var stringExpression = parse.Func(func(pi *parse.Input) (n Node, ok bool, err error) { + // Check the prefix first. + if _, ok, err = parse.Or(parse.String("{ "), parse.String("{")).Parse(pi); err != nil || !ok { + return + } + + // Once we have a prefix, we must have an expression that returns a string, with optional err. + var r StringExpression + if r.Expression, err = parseGoSliceArgs(pi); err != nil { + return r, false, err + } + + // Clear any optional whitespace. + _, _, _ = parse.OptionalWhitespace.Parse(pi) + + // } + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("string expression: missing close brace", pi.Position()) + return + } + + // Parse trailing whitespace. + ws, _, err := parse.Whitespace.Parse(pi) + if err != nil { + return r, false, err + } + r.TrailingSpace, err = NewTrailingSpace(ws) + if err != nil { + return r, false, err + } + + return r, true, nil +}) diff --git a/templ/parser/v2/stringexpressionparser_test.go b/templ/parser/v2/stringexpressionparser_test.go new file mode 100644 index 0000000..a5d4da3 --- /dev/null +++ b/templ/parser/v2/stringexpressionparser_test.go @@ -0,0 +1,108 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestStringExpressionParser(t *testing.T) { + var tests = []struct { + name string + input string + expected StringExpression + }{ + { + name: "basic expression", + input: `{ "this" }`, + expected: StringExpression{ + Expression: Expression{ + Value: `"this"`, + Range: Range{ + From: Position{ + Index: 2, + Line: 0, + Col: 2, + }, + To: Position{ + + Index: 8, + Line: 0, + Col: 8, + }, + }, + }, + }, + }, + { + name: "no spaces", + input: `{"this"}`, + expected: StringExpression{ + Expression: Expression{ + Value: `"this"`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + + Index: 7, + Line: 0, + Col: 7, + }, + }, + }, + }, + }, + { + name: "multiple lines", + input: `{ test{}.Call(a, + b, + c) }`, + expected: StringExpression{ + Expression: Expression{ + Value: "test{}.Call(a,\n\t\tb,\n\t c)", + Range: Range{ + From: Position{ + Index: 2, + Line: 0, + Col: 2, + }, + To: Position{ + + Index: 27, + Line: 2, + Col: 5, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + an, ok, err := stringExpression.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + actual := an.(StringExpression) + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + + // Check the index. + cut := tt.input[actual.Expression.Range.From.Index:actual.Expression.Range.To.Index] + if tt.expected.Expression.Value != cut { + t.Errorf("range, expected %q, got %q", tt.expected.Expression.Value, cut) + } + }) + } +} diff --git a/templ/parser/v2/structure.go b/templ/parser/v2/structure.go new file mode 100644 index 0000000..14e92bf --- /dev/null +++ b/templ/parser/v2/structure.go @@ -0,0 +1,42 @@ +package parser + +// TemplateFileNodes are the top level nodes of a templ file. +var ( + // css name() { ... } + _ TemplateFileNode = CSSTemplate{} + // templ name() { ... } + _ TemplateFileNode = HTMLTemplate{} + // script name() { ... } + _ TemplateFileNode = ScriptTemplate{} + // Go code within a templ file. + _ TemplateFileNode = TemplateFileGoExpression{} +) + +// Nodes are all the nodes you can find in a `templ` component. +var ( + _ Node = Text{} + _ Node = Element{} + _ Node = RawElement{} + _ Node = GoComment{} + _ Node = HTMLComment{} + _ Node = CallTemplateExpression{} + _ Node = TemplElementExpression{} + _ Node = ChildrenExpression{} + _ Node = IfExpression{} + _ Node = SwitchExpression{} + _ Node = ForExpression{} + _ Node = StringExpression{} + _ Node = GoCode{} + _ Node = Whitespace{} + _ Node = DocType{} +) + +// Element nodes can have the following attributes. +var ( + _ Attribute = BoolConstantAttribute{} + _ Attribute = ConstantAttribute{} + _ Attribute = BoolExpressionAttribute{} + _ Attribute = ExpressionAttribute{} + _ Attribute = SpreadAttributes{} + _ Attribute = ConditionalAttribute{} +) diff --git a/templ/parser/v2/switchexpressionparser.go b/templ/parser/v2/switchexpressionparser.go new file mode 100644 index 0000000..cbdb02c --- /dev/null +++ b/templ/parser/v2/switchexpressionparser.go @@ -0,0 +1,102 @@ +package parser + +import ( + "github.com/a-h/parse" + "github.com/a-h/templ/parser/v2/goexpression" +) + +var switchExpression parse.Parser[Node] = switchExpressionParser{} + +type switchExpressionParser struct{} + +func (switchExpressionParser) Parse(pi *parse.Input) (n Node, ok bool, err error) { + var r SwitchExpression + start := pi.Index() + + // Check the prefix first. + if !peekPrefix(pi, "switch ") { + pi.Seek(start) + return + } + + // Parse the Go switch expression. + if r.Expression, err = parseGo("switch", pi, goexpression.Switch); err != nil { + return r, false, err + } + + // Eat " {\n". + if _, ok, err = parse.All(openBraceWithOptionalPadding, parse.NewLine).Parse(pi); err != nil || !ok { + err = parse.Error("switch: "+unterminatedMissingCurly, pi.PositionAt(start)) + return + } + + // Once we've had the start of a switch block, we must conclude the block. + + // Read the optional 'case' nodes. + for { + var ce CaseExpression + ce, ok, err = caseExpressionParser.Parse(pi) + if err != nil { + return + } + if !ok { + break + } + r.Cases = append(r.Cases, ce) + } + + // Read the required closing brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("switch: "+unterminatedMissingEnd, pi.Position()) + return + } + + return r, true, nil +} + +var caseExpressionStartParser = parse.Func(func(pi *parse.Input) (r Expression, ok bool, err error) { + start := pi.Index() + + // Optional whitespace. + if _, _, err = parse.OptionalWhitespace.Parse(pi); err != nil { + return + } + + // Strip leading whitespace and look for `case ` or `default`. + if !peekPrefix(pi, "case ", "default") { + pi.Seek(start) + return r, false, nil + } + // Parse the Go expression. + if r, err = parseGo("case", pi, goexpression.Case); err != nil { + return r, false, err + } + + // Eat terminating newline. + _, _, _ = parse.ZeroOrMore(parse.String(" ")).Parse(pi) + _, _, _ = parse.NewLine.Parse(pi) + + return r, true, nil +}) + +var caseExpressionParser = parse.Func(func(pi *parse.Input) (r CaseExpression, ok bool, err error) { + if r.Expression, ok, err = caseExpressionStartParser.Parse(pi); err != nil || !ok { + return + } + + // Read until the next case statement, default, or end of the block. + pr := newTemplateNodeParser(parse.Any(StripType(closeBraceWithOptionalPadding), StripType(caseExpressionStartParser)), "closing brace or case expression") + var nodes Nodes + if nodes, ok, err = pr.Parse(pi); err != nil || !ok { + err = parse.Error("case: expected nodes, but none were found", pi.Position()) + return + } + r.Children = nodes.Nodes + + // Optional whitespace. + if _, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + + return r, true, nil +}) diff --git a/templ/parser/v2/switchexpressionparser_test.go b/templ/parser/v2/switchexpressionparser_test.go new file mode 100644 index 0000000..376d7ba --- /dev/null +++ b/templ/parser/v2/switchexpressionparser_test.go @@ -0,0 +1,349 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestSwitchExpressionParser(t *testing.T) { + tests := []struct { + name string + input string + expected SwitchExpression + }{ + { + name: "switch: simple", + input: `switch "stringy" { +}`, + expected: SwitchExpression{ + Expression: Expression{ + Value: `"stringy"`, + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + }, + }, + { + name: "switch: default only", + input: `switch "stringy" { +default: + + { "span content" } + +}`, + expected: SwitchExpression{ + Expression: Expression{ + Value: `"stringy"`, + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + Cases: []CaseExpression{ + { + Expression: Expression{ + Value: "default:", + Range: Range{ + From: Position{ + Index: 19, + Line: 1, + Col: 0, + }, + To: Position{ + Index: 27, + Line: 1, + Col: 8, + }, + }, + }, + Children: []Node{ + Whitespace{Value: "\t"}, + Element{ + Name: "span", + NameRange: Range{ + From: Position{Index: 30, Line: 2, Col: 2}, + To: Position{Index: 34, Line: 2, Col: 6}, + }, + Children: []Node{ + Whitespace{Value: "\n\t "}, + StringExpression{ + Expression: Expression{ + Value: `"span content"`, + Range: Range{ + From: Position{ + Index: 41, + Line: 3, + Col: 5, + }, + To: Position{ + Index: 55, + Line: 3, + Col: 19, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + IndentChildren: true, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + }, + }, + { + name: "switch: one case", + input: `switch "stringy" { + case "stringy": + + { "span content" } + +}`, + expected: SwitchExpression{ + Expression: Expression{ + Value: `"stringy"`, + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + Cases: []CaseExpression{ + { + Expression: Expression{ + Value: "case \"stringy\":", + Range: Range{ + From: Position{ + Index: 20, + Line: 1, + Col: 1, + }, + To: Position{ + Index: 35, + Line: 1, + Col: 16, + }, + }, + }, + Children: []Node{ + Element{ + Name: "span", + NameRange: Range{ + From: Position{Index: 37, Line: 2, Col: 1}, + To: Position{Index: 41, Line: 2, Col: 5}, + }, + Children: []Node{ + Whitespace{Value: "\n "}, + StringExpression{ + Expression: Expression{ + Value: `"span content"`, + Range: Range{ + From: Position{ + Index: 47, + Line: 3, + Col: 4, + }, + To: Position{ + Index: 61, + Line: 3, + Col: 18, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + IndentChildren: true, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + }, + }, + { + name: "switch: two cases", + input: `switch "stringy" { + case "a": + { "A" } + case "b": + { "B" } +}`, + expected: SwitchExpression{ + Expression: Expression{ + Value: `"stringy"`, + Range: Range{ + From: Position{ + Index: 7, + Line: 0, + Col: 7, + }, + To: Position{ + Index: 16, + Line: 0, + Col: 16, + }, + }, + }, + Cases: []CaseExpression{ + { + Expression: Expression{ + Value: "case \"a\":", + Range: Range{ + From: Position{ + Index: 20, + Line: 1, + Col: 1, + }, + To: Position{ + Index: 29, + Line: 1, + Col: 10, + }, + }, + }, + Children: []Node{ + Whitespace{ + Value: "\t\t", + }, + StringExpression{ + Expression: Expression{ + Value: `"A"`, + Range: Range{ + From: Position{ + Index: 34, + Line: 2, + Col: 4, + }, + To: Position{ + Index: 37, + Line: 2, + Col: 7, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + { + Expression: Expression{ + Value: "case \"b\":", + Range: Range{ + From: Position{ + Index: 41, + Line: 3, + Col: 1, + }, + To: Position{ + Index: 50, + Line: 3, + Col: 10, + }, + }, + }, + Children: []Node{ + Whitespace{ + Value: "\t\t", + }, + StringExpression{ + Expression: Expression{ + Value: `"B"`, + Range: Range{ + From: Position{ + Index: 55, + Line: 4, + Col: 4, + }, + To: Position{ + Index: 58, + Line: 4, + Col: 7, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := switchExpression.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestIncompleteSwitch(t *testing.T) { + t.Run("no opening brace", func(t *testing.T) { + input := parse.NewInput(`switch with no brace`) + _, _, err := switchExpression.Parse(input) + if err == nil { + t.Fatal("expected an error, got nil") + } + pe, isParseError := err.(parse.ParseError) + if !isParseError { + t.Fatalf("expected a parse error, got %T", err) + } + if pe.Msg != "switch: unterminated (missing closing '{\\n') - https://templ.guide/syntax-and-usage/statements#incomplete-statements" { + t.Errorf("unexpected error: %v", err) + } + if pe.Pos.Line != 0 { + t.Errorf("unexpected line: %d", pe.Pos.Line) + } + }) + t.Run("capitalised Switch", func(t *testing.T) { + input := parse.NewInput(`Switch with no brace`) + _, ok, err := switchExpression.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ok { + t.Fatal("expected a non match") + } + }) +} diff --git a/templ/parser/v2/templatefile.go b/templ/parser/v2/templatefile.go new file mode 100644 index 0000000..91efdfb --- /dev/null +++ b/templ/parser/v2/templatefile.go @@ -0,0 +1,193 @@ +package parser + +import ( + "errors" + "os" + "path/filepath" + "strings" + "unicode" + + "github.com/a-h/parse" +) + +func Parse(fileName string) (TemplateFile, error) { + fc, err := os.ReadFile(fileName) + if err != nil { + return TemplateFile{}, err + } + return ParseString(string(fc)) +} + +func getDefaultPackageName(fileName string) (pkg string) { + parent := filepath.Base(filepath.Dir(fileName)) + if !isGoIdentifier(parent) { + return "main" + } + return parent +} + +func isGoIdentifier(s string) bool { + if len(s) == 0 { + return false + } + for i, r := range s { + if unicode.IsLetter(r) || r == '_' { + continue + } + if i > 0 && unicode.IsDigit(r) { + continue + } + return false + } + return true +} + +func ParseString(template string) (TemplateFile, error) { + tf, ok, err := NewTemplateFileParser("main").Parse(parse.NewInput(template)) + if err != nil { + return tf, err + } + if !ok { + err = ErrTemplateNotFound + } + return tf, err +} + +// NewTemplateFileParser creates a new TemplateFileParser. +func NewTemplateFileParser(pkg string) TemplateFileParser { + return TemplateFileParser{ + DefaultPackage: pkg, + } +} + +var ErrLegacyFileFormat = errors.New("legacy file format - run templ migrate") +var ErrTemplateNotFound = errors.New("template not found") + +type TemplateFileParser struct { + DefaultPackage string +} + +var legacyPackageParser = parse.String("{% package") + +func (p TemplateFileParser) Parse(pi *parse.Input) (tf TemplateFile, ok bool, err error) { + // If we're parsing a legacy file, complain that migration needs to happen. + _, ok, err = legacyPackageParser.Parse(pi) + if err != nil { + return + } + if ok { + return tf, false, ErrLegacyFileFormat + } + + // Read until the package. + for { + // Package. + // package name + from := pi.Position() + tf.Package, ok, err = pkg.Parse(pi) + if err != nil { + return + } + if ok { + break + } + + var line string + line, ok, err = stringUntilNewLine.Parse(pi) + if err != nil { + return + } + if !ok { + break + } + var newLine string + newLine, _, _ = parse.NewLine.Parse(pi) + tf.Header = append(tf.Header, TemplateFileGoExpression{Expression: NewExpression(line+newLine, from, pi.Position()), BeforePackage: true}) + } + + // Strip any whitespace between the template declaration and the first template. + _, _, _ = parse.OptionalWhitespace.Parse(pi) + +outer: + for { + // Optional templates, CSS, and script templates. + // templ Name(p Parameter) + var tn HTMLTemplate + tn, ok, err = template.Parse(pi) + if err != nil { + return tf, false, err + } + if ok { + tf.Nodes = append(tf.Nodes, tn) + _, _, _ = parse.OptionalWhitespace.Parse(pi) + continue + } + + // css Name() + var cn CSSTemplate + cn, ok, err = cssParser.Parse(pi) + if err != nil { + return tf, false, err + } + if ok { + tf.Nodes = append(tf.Nodes, cn) + _, _, _ = parse.OptionalWhitespace.Parse(pi) + continue + } + + // script Name() + var sn ScriptTemplate + sn, ok, err = scriptTemplateParser.Parse(pi) + if err != nil { + return tf, false, err + } + if ok { + tf.Nodes = append(tf.Nodes, sn) + _, _, _ = parse.OptionalWhitespace.Parse(pi) + continue + } + + // Anything that isn't template content is Go code. + code := new(strings.Builder) + from := pi.Position() + inner: + for { + // Check to see if this line isn't Go code. + last := pi.Index() + var l string + if l, ok, err = stringUntilNewLineOrEOF.Parse(pi); err != nil { + return + } + hasTemplatePrefix := strings.HasPrefix(l, "templ ") || strings.HasPrefix(l, "css ") || strings.HasPrefix(l, "script ") + if hasTemplatePrefix && strings.Contains(l, "(") { + // Unread the line. + pi.Seek(last) + // Take the code so far. + if code.Len() > 0 { + expr := NewExpression(strings.TrimSpace(code.String()), from, pi.Position()) + tf.Nodes = append(tf.Nodes, TemplateFileGoExpression{Expression: expr}) + } + // Carry on parsing. + break inner + } + code.WriteString(l) + + // Eat the newline or EOF that we read until. + var newLine string + if newLine, ok, err = parse.NewLine.Parse(pi); err != nil { + return + } + code.WriteString(newLine) + if _, isEOF, _ := parse.EOF[string]().Parse(pi); isEOF { + if code.Len() > 0 { + expr := NewExpression(strings.TrimSpace(code.String()), from, pi.Position()) + tf.Nodes = append(tf.Nodes, TemplateFileGoExpression{Expression: expr}) + } + // Stop parsing. + break outer + } + } + } + + return tf, true, nil +} diff --git a/templ/parser/v2/templatefile_test.go b/templ/parser/v2/templatefile_test.go new file mode 100644 index 0000000..f7b7e21 --- /dev/null +++ b/templ/parser/v2/templatefile_test.go @@ -0,0 +1,195 @@ +package parser + +import ( + "reflect" + "testing" +) + +func TestTemplateFileParser(t *testing.T) { + t.Run("requests migration of legacy formats", func(t *testing.T) { + input := `{% package templates %} +` + _, err := ParseString(input) + if err == nil { + t.Error("expected ErrLegacyFileFormat, got nil") + } + if err != ErrLegacyFileFormat { + t.Errorf("expected ErrLegacyFileFormat, got %v", err) + } + }) + t.Run("but can accept a package expression, if one is provided", func(t *testing.T) { + input := `package goof + +templ Hello() { + Hello +}` + tf, err := ParseString(input) + if err != nil { + t.Fatalf("failed to parse template, with t.Fatalf(parser %v", err) + } + if len(tf.Nodes) != 1 { + t.Errorf("expected 2 nodes, got %+v", tf.Nodes) + } + if tf.Package.Expression.Value != "package goof" { + t.Errorf("expected \"goof\", got %q", tf.Package.Expression.Value) + } + }) + t.Run("can start with comments", func(t *testing.T) { + input := `// Example comment. +package goof + +templ Hello() { + Hello +}` + tf, err := ParseString(input) + if err != nil { + t.Fatalf("failed to parse template, with t.Fatalf(parser %v", err) + } + if len(tf.Nodes) != 1 { + t.Errorf("expected 2 node, got %d nodes with content %+v", len(tf.Nodes), tf.Nodes) + } + }) + t.Run("template files can end with Go expressions", func(t *testing.T) { + input := `package goof + +const x = "123" + +templ Hello() { + Hello +} + +const y = "456" +` + tf, err := ParseString(input) + if err != nil { + t.Fatalf("failed to parse template, with t.Fatalf(parser %v", err) + } + if len(tf.Nodes) != 3 { + var nodeTypes []string + for _, n := range tf.Nodes { + nodeTypes = append(nodeTypes, reflect.TypeOf(n).Name()) + } + t.Fatalf("expected 3 nodes, got %d nodes, %v", len(tf.Nodes), nodeTypes) + } + expr, isGoExpression := tf.Nodes[0].(TemplateFileGoExpression) + if !isGoExpression { + t.Errorf("0: expected expression, got %t", tf.Nodes[2]) + } + if expr.Expression.Value != `const x = "123"` { + t.Errorf("0: unexpected expression: %q", expr.Expression.Value) + } + expr, isGoExpression = tf.Nodes[2].(TemplateFileGoExpression) + if !isGoExpression { + t.Errorf("2: expected expression, got %t", tf.Nodes[2]) + } + if expr.Expression.Value != `const y = "456"` { + t.Errorf("2: unexpected expression: %q", expr.Expression.Value) + } + }) + t.Run("template files can end with string literals", func(t *testing.T) { + input := `package goof + +const x = "123" + +templ Hello() { + Hello +} + +const y = ` + "`456`" + tf, err := ParseString(input) + if err != nil { + t.Fatalf("failed to parse template, with t.Fatalf(parser %v", err) + } + if len(tf.Nodes) != 3 { + var nodeTypes []string + for _, n := range tf.Nodes { + nodeTypes = append(nodeTypes, reflect.TypeOf(n).Name()) + } + t.Fatalf("expected 3 nodes, got %d nodes, %v", len(tf.Nodes), nodeTypes) + } + expr, isGoExpression := tf.Nodes[0].(TemplateFileGoExpression) + if !isGoExpression { + t.Errorf("0: expected expression, got %t", tf.Nodes[2]) + } + if expr.Expression.Value != `const x = "123"` { + t.Errorf("0: unexpected expression: %q", expr.Expression.Value) + } + expr, isGoExpression = tf.Nodes[2].(TemplateFileGoExpression) + if !isGoExpression { + t.Errorf("2: expected expression, got %t", tf.Nodes[2]) + } + if expr.Expression.Value != "const y = `456`" { + t.Errorf("2: unexpected expression: %q", expr.Expression.Value) + } + }) + // https://github.com/a-h/templ/issues/505 + t.Run("template files can contain go expressions followed by multiline templates", func(t *testing.T) { + input := `package goof + +var a = "a" + +templ template( + a string, +) { +}` + tf, err := ParseString(input) + if err != nil { + t.Fatalf("failed to parse template, with t.Fatalf(parser %v", err) + } + if len(tf.Nodes) != 2 { + var nodeTypes []string + for _, n := range tf.Nodes { + nodeTypes = append(nodeTypes, reflect.TypeOf(n).Name()) + } + t.Fatalf("expected 2 nodes, got %d nodes, %v\n%#v", len(tf.Nodes), nodeTypes, tf) + } + expr, isGoExpression := tf.Nodes[0].(TemplateFileGoExpression) + if !isGoExpression { + t.Errorf("0: expected expression, got %t", tf.Nodes[2]) + } + if expr.Expression.Value != `var a = "a"` { + t.Errorf("0: unexpected expression: %q", expr.Expression.Value) + } + _, isGoExpression = tf.Nodes[1].(HTMLTemplate) + if !isGoExpression { + t.Errorf("2: expected expression, got %t", tf.Nodes[2]) + } + }) +} + +func TestDefaultPackageName(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "standard filename", + input: "/files/on/disk/header.templ", + expected: "disk", + }, + { + name: "path that starts with numbers", + input: "/files/on/123disk/header.templ", + expected: "main", + }, + { + name: "path that includes hyphens", + input: "/files/on/disk-drive/header.templ", + expected: "main", + }, + { + name: "relative path", + input: "header.templ", + expected: "main", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := getDefaultPackageName(tt.input) + if actual != tt.expected { + t.Errorf("expected %q got %q", tt.expected, actual) + } + }) + } +} diff --git a/templ/parser/v2/templateparser.go b/templ/parser/v2/templateparser.go new file mode 100644 index 0000000..1965637 --- /dev/null +++ b/templ/parser/v2/templateparser.go @@ -0,0 +1,149 @@ +package parser + +import ( + "fmt" + + "github.com/a-h/parse" +) + +// TemplateExpression. + +// TemplateExpression. +// templ Func(p Parameter) { +// templ (data Data) Func(p Parameter) { +// templ (data []string) Func(p Parameter) { +type templateExpression struct { + Expression Expression +} + +var templateExpressionParser = parse.Func(func(pi *parse.Input) (r templateExpression, ok bool, err error) { + start := pi.Index() + + if !peekPrefix(pi, "templ ") { + return r, false, nil + } + + // Once we have the prefix, everything to the brace is Go. + // e.g. + // templ (x []string) Test() { + // becomes: + // func (x []string) Test() templ.Component { + if _, r.Expression, err = parseTemplFuncDecl(pi); err != nil { + return r, false, err + } + + // Eat " {\n". + if _, ok, err = parse.All(openBraceWithOptionalPadding, parse.StringFrom(parse.Optional(parse.NewLine))).Parse(pi); err != nil || !ok { + err = parse.Error("templ: malformed templ expression, expected `templ functionName() {`", pi.PositionAt(start)) + return + } + + return r, true, nil +}) + +const ( + unterminatedMissingCurly = `unterminated (missing closing '{\n') - https://templ.guide/syntax-and-usage/statements#incomplete-statements` + unterminatedMissingEnd = `missing end (expected '}') - https://templ.guide/syntax-and-usage/statements#incomplete-statements` +) + +// Template node (element, call, if, switch, for, whitespace etc.) +func newTemplateNodeParser[TUntil any](until parse.Parser[TUntil], untilName string) templateNodeParser[TUntil] { + return templateNodeParser[TUntil]{ + until: until, + untilName: untilName, + } +} + +type templateNodeParser[TUntil any] struct { + until parse.Parser[TUntil] + untilName string +} + +var rawElements = parse.Any(styleElement, scriptElement) + +var templateNodeSkipParsers = []parse.Parser[Node]{ + voidElementCloser, //
    , etc. - should be ignored. +} + +var templateNodeParsers = []parse.Parser[Node]{ + docType, // + htmlComment, // + +}`, + expected: HTMLTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 59, Line: 5, Col: 1}, + }, + Expression: Expression{ + Value: "x()", + Range: Range{ + From: Position{Index: 6, Line: 0, Col: 6}, + To: Position{Index: 9, Line: 0, Col: 9}, + }, + }, + Children: []Node{ + Whitespace{Value: "\t"}, + HTMLComment{Contents: " Single line "}, + Whitespace{Value: "\n\t"}, + HTMLComment{Contents: " \n\t\tMultiline\n\t"}, + Whitespace{Value: "\n"}, + }, + }, + }, + { + name: "template: containing spread attributes and children expression", + input: `templ Name(children templ.Attributes) { + + { children... } + +}`, + expected: HTMLTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 95, Line: 4, Col: 1}, + }, + Expression: Expression{ + Value: "Name(children templ.Attributes)", + Range: Range{ + From: Position{ + Index: 6, + Line: 0, + Col: 6, + }, + To: Position{ + Index: 37, + Line: 0, + Col: 37, + }, + }, + }, + Children: []Node{ + Whitespace{Value: "\t\t"}, + Element{ + Name: "span", + NameRange: Range{ + From: Position{Index: 43, Line: 1, Col: 3}, + To: Position{Index: 47, Line: 1, Col: 7}, + }, + Attributes: []Attribute{SpreadAttributes{ + Expression{ + Value: "children", + Range: Range{ + From: Position{ + Index: 50, + Line: 1, + Col: 10, + }, + To: Position{ + Index: 58, + Line: 1, + Col: 18, + }, + }, + }, + }}, + Children: []Node{ + Whitespace{"\n\t\t\t"}, + ChildrenExpression{}, + Whitespace{Value: "\n\t\t"}, + }, + IndentChildren: true, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + { + name: "template: void element closers are ignored", + input: `templ Name() { +


    +}`, + expected: HTMLTemplate{ + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 31, Line: 2, Col: 1}, + }, + Expression: Expression{ + Value: "Name()", + Range: Range{ + From: Position{Index: 6, Line: 0, Col: 6}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + Children: []Node{ + Whitespace{Value: "\t"}, + Element{ + Name: "br", + NameRange: Range{ + From: Position{Index: 17, Line: 1, Col: 2}, + To: Position{Index: 19, Line: 1, Col: 4}, + }, + TrailingSpace: SpaceNone, + }, + Element{ + Name: "br", + NameRange: Range{ + From: Position{Index: 26, Line: 1, Col: 11}, + To: Position{Index: 28, Line: 1, Col: 13}, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := template.Parse(input) + diff := cmp.Diff(tt.expected, actual) + switch { + case tt.expectError && err == nil: + t.Errorf("expected an error got nil: %+v", actual) + case !tt.expectError && err != nil: + t.Errorf("unexpected error: %v", err) + case tt.expectError && ok: + t.Errorf("Success=%v want=%v", ok, !tt.expectError) + case !tt.expectError && diff != "": + t.Error(diff) + } + }) + } +} + +func TestTemplateParserErrors(t *testing.T) { + var tests = []struct { + name string + input string + expected string + }{ + { + name: "template: containing element", + input: `templ Name(p Parameter) { +: malformed open element: line 3, col 0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + _, ok, err := template.Parse(input) + if err == nil { + t.Fatalf("expected error %q, got nil", tt.expected) + } + if ok { + t.Error("expected failure, but got success") + } + if diff := cmp.Diff(tt.expected, err.Error()); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/parser/v2/templelementparser.go b/templ/parser/v2/templelementparser.go new file mode 100644 index 0000000..9a50b5b --- /dev/null +++ b/templ/parser/v2/templelementparser.go @@ -0,0 +1,52 @@ +package parser + +import ( + "github.com/a-h/parse" + "github.com/a-h/templ/parser/v2/goexpression" +) + +type templElementExpressionParser struct{} + +func (p templElementExpressionParser) Parse(pi *parse.Input) (n Node, ok bool, err error) { + // Check the prefix first. + if _, ok, err = parse.Rune('@').Parse(pi); err != nil || !ok { + return + } + + var r TemplElementExpression + // Parse the Go expression. + if r.Expression, err = parseGo("templ element", pi, goexpression.TemplExpression); err != nil { + return r, false, err + } + + // Once we've got a start expression, check to see if there's an open brace for children. {\n. + var hasOpenBrace bool + _, hasOpenBrace, err = openBraceWithOptionalPadding.Parse(pi) + if err != nil { + return + } + if !hasOpenBrace { + return r, true, nil + } + + // Once we've had the start of an element's children, we must conclude the block. + + // Node contents. + np := newTemplateNodeParser(closeBraceWithOptionalPadding, "templ element closing brace") + var nodes Nodes + if nodes, ok, err = np.Parse(pi); err != nil || !ok { + err = parse.Error("@"+r.Expression.Value+": expected nodes, but none were found", pi.Position()) + return + } + r.Children = nodes.Nodes + + // Read the required closing brace. + if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok { + err = parse.Error("@"+r.Expression.Value+": missing end (expected '}')", pi.Position()) + return + } + + return r, true, nil +} + +var templElementExpression templElementExpressionParser diff --git a/templ/parser/v2/templelementparser_test.go b/templ/parser/v2/templelementparser_test.go new file mode 100644 index 0000000..ec5c584 --- /dev/null +++ b/templ/parser/v2/templelementparser_test.go @@ -0,0 +1,484 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestTemplElementExpressionParser(t *testing.T) { + tests := []struct { + name string + input string + expected TemplElementExpression + }{ + { + name: "templelement: simple", + input: `@Other(p.Test)` + "\n", + expected: TemplElementExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 14, + Line: 0, + Col: 14, + }, + }, + }, + }, + }, + { + name: "templelement: simple with underscore", + input: `@Other_Component(p.Test)` + "\n", + expected: TemplElementExpression{ + Expression: Expression{ + Value: "Other_Component(p.Test)", + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 24, + Line: 0, + Col: 24, + }, + }, + }, + }, + }, + { + name: "templelement: simple multiline call", + input: `@Other_Component( + p.Test, + "something" + "else", + )` + "\n", + expected: TemplElementExpression{ + Expression: Expression{ + Value: `Other_Component( + p.Test, + "something" + "else", + )`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 60, + Line: 3, + Col: 4, + }, + }, + }, + }, + }, + { + name: "templelement: simple, block with text", + input: `@Other(p.Test) { + some words +}`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 14, + Line: 0, + Col: 14, + }, + }, + }, + Children: []Node{ + Whitespace{Value: "\n\t"}, + Text{ + Value: "some words", + Range: Range{ + From: Position{Index: 18, Line: 1, Col: 1}, + To: Position{Index: 28, Line: 1, Col: 11}, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + { + name: "templelement: simple, block with anchor", + input: `@Other(p.Test){ +
    + }`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 14, + Line: 0, + Col: 14, + }, + }, + }, + Children: []Node{ + Whitespace{Value: "\n\t\t\t"}, + Element{Name: "a", + NameRange: Range{ + From: Position{Index: 20, Line: 1, Col: 4}, + To: Position{Index: 21, Line: 1, Col: 5}, + }, + Attributes: []Attribute{ + ConstantAttribute{ + Name: "href", + Value: "someurl", + NameRange: Range{ + From: Position{Index: 22, Line: 1, Col: 6}, + To: Position{Index: 26, Line: 1, Col: 10}, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + { + name: "templelement: simple, block with templelement as child", + input: `@Other(p.Test) { + @other2 + }`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: "Other(p.Test)", + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 14, + Line: 0, + Col: 14, + }, + }, + }, + Children: []Node{ + Whitespace{Value: "\n\t\t\t\t"}, + TemplElementExpression{ + Expression: Expression{ + Value: "other2", + Range: Range{ + From: Position{22, 1, 5}, + To: Position{28, 1, 11}, + }, + }, + }, + Whitespace{Value: "\n\t\t\t"}, + }, + }, + }, + { + name: "templelement: can parse the initial expression and leave the text", + input: `@Icon("home", Inline) Home +}`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `Icon("home", Inline)`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 21, + Line: 0, + Col: 21, + }, + }, + }, + }, + }, + { + name: "templelement: supports the use of templ elements in other packages", + input: `@templates.Icon("home", Inline)`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates.Icon("home", Inline)`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 31, + Line: 0, + Col: 31, + }, + }, + }, + }, + }, + { + name: "templelement: supports the use of params which contain braces and params", + input: `@templates.New(test{}, other())`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates.New(test{}, other())`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 31, + Line: 0, + Col: 31, + }, + }, + }, + }, + }, + { + name: "templelement: supports a slice of functions", + input: `@templates[0]()`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates[0]()`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 15, + Line: 0, + Col: 15, + }, + }, + }, + }, + }, + { + name: "templelement: supports a map of functions", + input: `@templates["key"]()`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates["key"]()`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 19, + Line: 0, + Col: 19, + }, + }, + }, + }, + }, + { + name: "templelement: supports a slice of structs/interfaces", + input: `@templates[0].CreateTemplate()`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates[0].CreateTemplate()`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 30, + Line: 0, + Col: 30, + }, + }, + }, + }, + }, + { + name: "templelement: supports a slice of structs/interfaces", + input: `@templates[0].CreateTemplate()`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `templates[0].CreateTemplate()`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 30, + Line: 0, + Col: 30, + }, + }, + }, + }, + }, + { + name: "templelement: bare variables are read until the end of the token", + input: `@template
    `, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `template`, + Range: Range{ + From: Position{ + Index: 1, + Line: 0, + Col: 1, + }, + To: Position{ + Index: 9, + Line: 0, + Col: 9, + }, + }, + }, + }, + }, + { + name: "templelement: struct literal method calls are supported", + input: `@layout.DefaultLayout{}.Compile()
    `, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `layout.DefaultLayout{}.Compile()`, + Range: Range{ + From: Position{1, 0, 1}, + To: Position{33, 0, 33}, + }, + }, + }, + }, + { + name: "templelement: struct literal method calls are supported, with child elements", + input: `@layout.DefaultLayout{}.Compile() { +
    hello
    +}`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `layout.DefaultLayout{}.Compile()`, + Range: Range{ + From: Position{1, 0, 1}, + To: Position{33, 0, 33}, + }, + }, + Children: []Node{ + Whitespace{Value: "\n "}, + Element{ + Name: "div", + NameRange: Range{ + From: Position{Index: 39, Line: 1, Col: 3}, + To: Position{Index: 42, Line: 1, Col: 6}, + }, + Children: []Node{ + Text{ + Value: "hello", + Range: Range{ + From: Position{Index: 43, Line: 1, Col: 7}, + To: Position{Index: 48, Line: 1, Col: 12}, + }, + }, + }, + TrailingSpace: SpaceVertical, + }, + }, + }, + }, + { + name: "templelement: arguments can receive a slice of complex types", + input: `@tabs([]*TabData{ + {Name: "A"}, + {Name: "B"}, +})`, + expected: TemplElementExpression{ + Expression: Expression{ + Value: `tabs([]*TabData{ + {Name: "A"}, + {Name: "B"}, +})`, + Range: Range{ + From: Position{1, 0, 1}, + To: Position{50, 3, 2}, + }, + }, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := templElementExpression.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestTemplElementExpressionParserFailures(t *testing.T) { + tests := []struct { + name string + input string + }{ + { + name: "templelement: missing closing brace", + input: `@SplitRule(types.GroupMember{ + UserID: uuid.NewString(), + Username: "user me", +}, []types.GroupMember{ + { + UserID: uuid.NewString(), + Username: "user 1", + }, +`, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + _, ok, err := templElementExpression.Parse(input) + if err == nil { + t.Fatalf("expected an error") + } + if ok { + t.Fatalf("expected a failure") + } + }) + } +} diff --git a/templ/parser/v2/textparser.go b/templ/parser/v2/textparser.go new file mode 100644 index 0000000..d5353a9 --- /dev/null +++ b/templ/parser/v2/textparser.go @@ -0,0 +1,53 @@ +package parser + +import ( + "unicode" + + "github.com/a-h/parse" +) + +var tagTemplOrNewLine = parse.Any(parse.Rune('<'), parse.Rune('{'), parse.Rune('}'), parse.String("\r\n"), parse.Rune('\n')) + +var textParser = parse.Func(func(pi *parse.Input) (n Node, ok bool, err error) { + from := pi.Position() + + // Read until a tag or templ expression opens. + var t Text + if t.Value, ok, err = parse.StringUntil(tagTemplOrNewLine).Parse(pi); err != nil || !ok { + return + } + if isWhitespace(t.Value) { + return t, false, nil + } + if _, ok = pi.Peek(1); !ok { + err = parse.Error("textParser: unterminated text, expected tag open, templ expression open, or newline", from) + return + } + t.Range = NewRange(from, pi.Position()) + + // Elide any void element closing tags. + if _, _, err = voidElementCloser.Parse(pi); err != nil { + return + } + + // Parse trailing whitespace. + ws, _, err := parse.Whitespace.Parse(pi) + if err != nil { + return t, false, err + } + t.TrailingSpace, err = NewTrailingSpace(ws) + if err != nil { + return t, false, err + } + + return t, true, nil +}) + +func isWhitespace(s string) bool { + for _, r := range s { + if !unicode.IsSpace(r) { + return false + } + } + return true +} diff --git a/templ/parser/v2/textparser_test.go b/templ/parser/v2/textparser_test.go new file mode 100644 index 0000000..d6b25d1 --- /dev/null +++ b/templ/parser/v2/textparser_test.go @@ -0,0 +1,123 @@ +package parser + +import ( + "testing" + + "github.com/a-h/parse" + "github.com/google/go-cmp/cmp" +) + +func TestTextParser(t *testing.T) { + var tests = []struct { + name string + input string + expected Text + }{ + { + name: "Text ends at an element start", + input: `abcdefMore`, + expected: Text{ + Value: "abcdef", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + }, + }, + { + name: "Text ends at a templ expression start", + input: `abcdef{ "test" }`, + expected: Text{ + Value: "abcdef", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + }, + }, + { + name: "Text may contain spaces", + input: `abcdef ghijk{ "test" }`, + expected: Text{ + Value: "abcdef ghijk", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 12, Line: 0, Col: 12}, + }, + }, + }, + { + name: "Text may contain named references", + input: `abcdef ghijk{ "test" }`, + expected: Text{ + Value: "abcdef ghijk", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 17, Line: 0, Col: 17}, + }, + }, + }, + { + name: "Text may contain base 10 numeric references", + input: `abcdef ghijk{ "test" }`, + expected: Text{ + Value: "abcdef ghijk", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 16, Line: 0, Col: 16}, + }, + }, + }, + { + name: "Text may contain hexadecimal numeric references", + input: `abcdef ghijk{ "test" }`, + expected: Text{ + Value: "abcdef ghijk", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 17, Line: 0, Col: 17}, + }, + }, + }, + { + name: "Multiline text is collected line by line", + input: "Line 1\nLine 2", + expected: Text{ + Value: "Line 1", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + TrailingSpace: "\n", + }, + }, + { + name: "Multiline text is collected line by line (Windows)", + input: "Line 1\r\nLine 2", + expected: Text{ + Value: "Line 1", + Range: Range{ + From: Position{Index: 0, Line: 0, Col: 0}, + To: Position{Index: 6, Line: 0, Col: 6}, + }, + TrailingSpace: "\n", + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + input := parse.NewInput(tt.input) + actual, ok, err := textParser.Parse(input) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ok { + t.Fatalf("unexpected failure for input %q", tt.input) + } + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Error(diff) + } + }) + } +} diff --git a/templ/parser/v2/types.go b/templ/parser/v2/types.go new file mode 100644 index 0000000..e4d47bc --- /dev/null +++ b/templ/parser/v2/types.go @@ -0,0 +1,1213 @@ +package parser + +import ( + "bytes" + "errors" + "fmt" + "go/format" + "io" + "strings" + "unicode" + + "github.com/a-h/parse" +) + +// package parser +// +// import "strings" +// import strs "strings" +// +// css AddressLineStyle() { +// background-color: #ff0000; +// color: #ffffff; +// } +// +// templ RenderAddress(addr Address) { +//
    { addr.Address1 }
    +//
    { addr.Address2 }
    +//
    { addr.Address3 }
    +//
    { addr.Address4 }
    +// } +// +// templ Render(p Person) { +//
    +//
    { p.Name() }
    +// { strings.ToUpper(p.Name()) } +//
    +// if p.Type == "test" { +// { "Test user" } +// } else { +// { "Not test user" } +// } +// for _, v := range p.Addresses { +// {! call RenderAddress(v) } +// } +//
    +//
    +// } + +// Source mapping to map from the source code of the template to the +// in-memory representation. +type Position struct { + Index int64 + Line uint32 + Col uint32 +} + +func (p Position) String() string { + return fmt.Sprintf("line %d, col %d (index %d)", p.Line, p.Col, p.Index) +} + +// NewPosition initialises a position. +func NewPosition(index int64, line, col uint32) Position { + return Position{ + Index: index, + Line: line, + Col: col, + } +} + +// NewExpression creates a Go expression. +func NewExpression(value string, from, to parse.Position) Expression { + return Expression{ + Value: value, + Range: Range{ + From: Position{ + Index: int64(from.Index), + Line: uint32(from.Line), + Col: uint32(from.Col), + }, + To: Position{ + Index: int64(to.Index), + Line: uint32(to.Line), + Col: uint32(to.Col), + }, + }, + } +} + +// NewRange creates a Range expression. +func NewRange(from, to parse.Position) Range { + return Range{ + From: Position{ + Index: int64(from.Index), + Line: uint32(from.Line), + Col: uint32(from.Col), + }, + To: Position{ + Index: int64(to.Index), + Line: uint32(to.Line), + Col: uint32(to.Col), + }, + } +} + +// Range of text within a file. +type Range struct { + From Position + To Position +} + +// Expression containing Go code. +type Expression struct { + Value string + Range Range +} + +type TemplateFile struct { + // Header contains comments or whitespace at the top of the file. + Header []TemplateFileGoExpression + // Package expression. + Package Package + // Filepath is where the file was loaded from. It is not always available. + Filepath string + // Nodes in the file. + Nodes []TemplateFileNode +} + +func (tf TemplateFile) Write(w io.Writer) error { + for _, n := range tf.Header { + if err := n.Write(w, 0); err != nil { + return err + } + } + var indent int + if err := tf.Package.Write(w, indent); err != nil { + return err + } + if _, err := io.WriteString(w, "\n\n"); err != nil { + return err + } + for i := 0; i < len(tf.Nodes); i++ { + if err := tf.Nodes[i].Write(w, indent); err != nil { + return err + } + if _, err := io.WriteString(w, getNodeWhitespace(tf.Nodes, i)); err != nil { + return err + } + } + return nil +} + +func getNodeWhitespace(nodes []TemplateFileNode, i int) string { + if i == len(nodes)-1 { + return "\n" + } + if _, nextIsTemplate := nodes[i+1].(HTMLTemplate); nextIsTemplate { + if e, isGo := nodes[i].(TemplateFileGoExpression); isGo && endsWithComment(e.Expression.Value) { + return "\n" + } + } + return "\n\n" +} + +func endsWithComment(s string) bool { + lineSlice := strings.Split(s, "\n") + return strings.HasPrefix(lineSlice[len(lineSlice)-1], "//") +} + +// TemplateFileNode can be a Template, CSS, Script or Go. +type TemplateFileNode interface { + IsTemplateFileNode() bool + Write(w io.Writer, indent int) error +} + +// TemplateFileGoExpression within a TemplateFile +type TemplateFileGoExpression struct { + Expression Expression + BeforePackage bool +} + +func (exp TemplateFileGoExpression) IsTemplateFileNode() bool { return true } +func (exp TemplateFileGoExpression) Write(w io.Writer, indent int) error { + in := exp.Expression.Value + + if exp.BeforePackage { + in += "\\\\formatstring\npackage p\n\\\\formatstring" + } + data, err := format.Source([]byte(in)) + if err != nil { + return writeIndent(w, indent, exp.Expression.Value) + } + if exp.BeforePackage { + data = bytes.TrimSuffix(data, []byte("\\\\formatstring\npackage p\n\\\\formatstring")) + } + _, err = w.Write(data) + return err +} + +func writeIndent(w io.Writer, level int, s ...string) (err error) { + indent := strings.Repeat("\t", level) + if _, err = io.WriteString(w, indent); err != nil { + return err + } + for _, ss := range s { + _, err = io.WriteString(w, ss) + if err != nil { + return + } + } + return +} + +type Package struct { + Expression Expression +} + +func (p Package) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, p.Expression.Value) +} + +// Whitespace. +type Whitespace struct { + Value string +} + +func (ws Whitespace) IsNode() bool { return true } + +func (ws Whitespace) Write(w io.Writer, indent int) error { + if ws.Value == "" || !strings.Contains(ws.Value, "\n") { + return nil + } + // https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Whitespace + // - All spaces and tabs immediately before and after a line break are ignored. + // - All tab characters are handled as space characters. + // - Line breaks are converted to spaces. + // Any space immediately following another space (even across two separate inline elements) is ignored. + // Sequences of spaces at the beginning and end of an element are removed. + + // Notes: Since we only have whitespace in this node, we can strip anything that isn't a line break. + // Since any space following another space is ignored, we can collapse to a single rule. + // So, the rule is... if there's a newline, it becomes a single space, or it's stripped. + // We have to remove the start and end space elsewhere. + _, err := io.WriteString(w, " ") + return err +} + +// CSS definition. +// +// css Name() { +// color: #ffffff; +// background-color: { constants.BackgroundColor }; +// background-image: url('./somewhere.png'); +// } +type CSSTemplate struct { + Range Range + Name string + Expression Expression + Properties []CSSProperty +} + +func (css CSSTemplate) IsTemplateFileNode() bool { return true } +func (css CSSTemplate) Write(w io.Writer, indent int) error { + source := formatFunctionArguments(css.Expression.Value) + if err := writeIndent(w, indent, "css ", string(source), " {\n"); err != nil { + return err + } + for _, p := range css.Properties { + if err := p.Write(w, indent+1); err != nil { + return err + } + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// CSSProperty is a CSS property and value pair. +type CSSProperty interface { + IsCSSProperty() bool + Write(w io.Writer, indent int) error +} + +// color: #ffffff; +type ConstantCSSProperty struct { + Name string + Value string +} + +func (c ConstantCSSProperty) IsCSSProperty() bool { return true } +func (c ConstantCSSProperty) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, c.String(false)); err != nil { + return err + } + return nil +} + +func (c ConstantCSSProperty) String(minified bool) string { + sb := new(strings.Builder) + sb.WriteString(c.Name) + if minified { + sb.WriteString(":") + } else { + sb.WriteString(": ") + } + sb.WriteString(c.Value) + sb.WriteString(";") + if !minified { + sb.WriteString("\n") + } + return sb.String() +} + +// background-color: { constants.BackgroundColor }; +type ExpressionCSSProperty struct { + Name string + Value StringExpression +} + +func (c ExpressionCSSProperty) IsCSSProperty() bool { return true } +func (c ExpressionCSSProperty) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, c.Name, ": "); err != nil { + return err + } + if err := c.Value.Write(w, 0); err != nil { + return err + } + if _, err := w.Write([]byte(";\n")); err != nil { + return err + } + return nil +} + +// +type DocType struct { + Value string +} + +func (dt DocType) IsNode() bool { return true } +func (dt DocType) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, "") +} + +// HTMLTemplate definition. +// +// templ Name(p Parameter) { +// if ... { +// +// } +// } +type HTMLTemplate struct { + Range Range + Expression Expression + Children []Node +} + +func (t HTMLTemplate) IsTemplateFileNode() bool { return true } + +func (t HTMLTemplate) Write(w io.Writer, indent int) error { + source := formatFunctionArguments(t.Expression.Value) + if err := writeIndent(w, indent, "templ ", string(source), " {\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, t.Children); err != nil { + return err + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// TrailingSpace defines the whitespace that may trail behind the close of an element, a +// text node, or string expression. +type TrailingSpace string + +const ( + SpaceNone TrailingSpace = "" + SpaceHorizontal TrailingSpace = " " + SpaceVertical TrailingSpace = "\n" +) + +var ErrNonSpaceCharacter = errors.New("non space character found") + +func NewTrailingSpace(s string) (ts TrailingSpace, err error) { + var hasHorizontalSpace bool + for _, r := range s { + if r == '\n' { + return SpaceVertical, nil + } + if unicode.IsSpace(r) { + hasHorizontalSpace = true + continue + } + return ts, ErrNonSpaceCharacter + } + if hasHorizontalSpace { + return SpaceHorizontal, nil + } + return SpaceNone, nil +} + +type Nodes struct { + Nodes []Node +} + +// A Node appears within a template, e.g. an StringExpression, Element, IfExpression etc. +type Node interface { + IsNode() bool + // Write out the string. + Write(w io.Writer, indent int) error +} + +type CompositeNode interface { + Node + ChildNodes() []Node +} + +type WhitespaceTrailer interface { + Trailing() TrailingSpace +} + +var ( + _ WhitespaceTrailer = Element{} + _ WhitespaceTrailer = Text{} + _ WhitespaceTrailer = StringExpression{} +) + +// Text node within the document. +type Text struct { + // Range of the text within the templ file. + Range Range + // Value is the raw HTML encoded value. + Value string + // TrailingSpace lists what happens after the text. + TrailingSpace TrailingSpace +} + +func (t Text) Trailing() TrailingSpace { + return t.TrailingSpace +} + +func (t Text) IsNode() bool { return true } +func (t Text) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, t.Value) +} + +// or
    ...
    +type Element struct { + Name string + Attributes []Attribute + IndentAttrs bool + Children []Node + IndentChildren bool + TrailingSpace TrailingSpace + NameRange Range +} + +func (e Element) Trailing() TrailingSpace { + return e.TrailingSpace +} + +var voidElements = map[string]struct{}{ + "area": {}, "base": {}, "br": {}, "col": {}, "command": {}, "embed": {}, "hr": {}, "img": {}, "input": {}, "keygen": {}, "link": {}, "meta": {}, "param": {}, "source": {}, "track": {}, "wbr": {}, +} + +// https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-element +func (e Element) IsVoidElement() bool { + _, ok := voidElements[e.Name] + return ok +} + +func (e Element) hasNonWhitespaceChildren() bool { + for _, c := range e.Children { + if _, isWhitespace := c.(Whitespace); !isWhitespace { + return true + } + } + return false +} + +var blockElements = map[string]struct{}{ + "address": {}, "article": {}, "aside": {}, "body": {}, "blockquote": {}, "canvas": {}, "dd": {}, "div": {}, "dl": {}, "dt": {}, "fieldset": {}, "figcaption": {}, "figure": {}, "footer": {}, "form": {}, "h1": {}, "h2": {}, "h3": {}, "h4": {}, "h5": {}, "h6": {}, "head": {}, "header": {}, "hr": {}, "html": {}, "li": {}, "main": {}, "meta": {}, "nav": {}, "noscript": {}, "ol": {}, "p": {}, "pre": {}, "script": {}, "section": {}, "table": {}, "template": {}, "tfoot": {}, "turbo-stream": {}, "ul": {}, "video": {}, + // Not strictly block but for the purposes of layout, they are. + "title": {}, "style": {}, "link": {}, "td": {}, "th": {}, "tr": {}, "br": {}, +} + +func (e Element) IsBlockElement() bool { + _, ok := blockElements[e.Name] + return ok +} + +// Validate that no invalid expressions have been used. +func (e Element) Validate() (msgs []string, ok bool) { + // Validate that script and style tags don't contain expressions. + if strings.EqualFold(e.Name, "script") || strings.EqualFold(e.Name, "style") { + if containsNonTextNodes(e.Children) { + msgs = append(msgs, "invalid node contents: script and style attributes must only contain text") + } + } + return msgs, len(msgs) == 0 +} + +func containsNonTextNodes(nodes []Node) bool { + for i := 0; i < len(nodes); i++ { + n := nodes[i] + switch n.(type) { + case Text: + continue + case Whitespace: + continue + default: + return true + } + } + return false +} + +func (e Element) ChildNodes() []Node { + return e.Children +} +func (e Element) IsNode() bool { return true } +func (e Element) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, "<", e.Name); err != nil { + return err + } + for i := 0; i < len(e.Attributes); i++ { + a := e.Attributes[i] + // Only the conditional attributes get indented. + var attrIndent int + if e.IndentAttrs { + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + attrIndent = indent + 1 + } else { + if _, err := w.Write([]byte(" ")); err != nil { + return err + } + } + if err := a.Write(w, attrIndent); err != nil { + return err + } + } + var closeAngleBracketIndent int + if e.IndentAttrs { + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + closeAngleBracketIndent = indent + } + if e.hasNonWhitespaceChildren() { + if e.IndentChildren { + if err := writeIndent(w, closeAngleBracketIndent, ">\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, e.Children); err != nil { + return err + } + if err := writeIndent(w, indent, ""); err != nil { + return err + } + return nil + } + if err := writeIndent(w, closeAngleBracketIndent, ">"); err != nil { + return err + } + if err := writeNodesWithoutIndentation(w, e.Children); err != nil { + return err + } + if _, err := w.Write([]byte("")); err != nil { + return err + } + return nil + } + if e.IsVoidElement() { + if err := writeIndent(w, closeAngleBracketIndent, "/>"); err != nil { + return err + } + return nil + } + if err := writeIndent(w, closeAngleBracketIndent, ">"); err != nil { + return err + } + return nil +} + +func writeNodesWithoutIndentation(w io.Writer, nodes []Node) error { + return writeNodes(w, 0, nodes, false) +} + +func writeNodesIndented(w io.Writer, level int, nodes []Node) error { + return writeNodes(w, level, nodes, true) +} + +func writeNodes(w io.Writer, level int, nodes []Node, indent bool) error { + startLevel := level + for i := 0; i < len(nodes); i++ { + _, isWhitespace := nodes[i].(Whitespace) + + // Skip whitespace nodes. + if isWhitespace { + continue + } + if err := nodes[i].Write(w, level); err != nil { + return err + } + + // Apply trailing whitespace if present. + trailing := SpaceVertical + if wst, isWhitespaceTrailer := nodes[i].(WhitespaceTrailer); isWhitespaceTrailer { + trailing = wst.Trailing() + } + // Put a newline after the last node in indentation mode. + if indent && ((nextNodeIsBlock(nodes, i) || i == len(nodes)-1) || shouldAlwaysBreakAfter(nodes[i])) { + trailing = SpaceVertical + } + switch trailing { + case SpaceNone: + level = 0 + case SpaceHorizontal: + level = 0 + case SpaceVertical: + level = startLevel + } + if _, err := w.Write([]byte(trailing)); err != nil { + return err + } + } + return nil +} + +func shouldAlwaysBreakAfter(node Node) bool { + if el, isElement := node.(Element); isElement { + return strings.EqualFold(el.Name, "br") || strings.EqualFold(el.Name, "hr") + } + return false +} + +func nextNodeIsBlock(nodes []Node, i int) bool { + if len(nodes)-1 < i+1 { + return false + } + return isBlockNode(nodes[i+1]) +} + +func isBlockNode(node Node) bool { + switch n := node.(type) { + case IfExpression: + return true + case SwitchExpression: + return true + case ForExpression: + return true + case Element: + return n.IsBlockElement() || n.IndentChildren + } + return false +} + +type RawElement struct { + Name string + Attributes []Attribute + Contents string +} + +func (e RawElement) IsNode() bool { return true } +func (e RawElement) Write(w io.Writer, indent int) error { + // Start. + if err := writeIndent(w, indent, "<", e.Name); err != nil { + return err + } + for i := 0; i < len(e.Attributes); i++ { + if _, err := w.Write([]byte(" ")); err != nil { + return err + } + a := e.Attributes[i] + // Don't indent the attributes, only the conditional attributes get indented. + if err := a.Write(w, 0); err != nil { + return err + } + } + if _, err := w.Write([]byte(">")); err != nil { + return err + } + // Contents. + if _, err := w.Write([]byte(e.Contents)); err != nil { + return err + } + // Close. + if _, err := w.Write([]byte("")); err != nil { + return err + } + return nil +} + +type Attribute interface { + // Write out the string. + Write(w io.Writer, indent int) error +} + +//
    +type BoolConstantAttribute struct { + Name string + NameRange Range +} + +func (bca BoolConstantAttribute) String() string { + return bca.Name +} + +func (bca BoolConstantAttribute) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, bca.String()) +} + +// href="" +type ConstantAttribute struct { + Name string + Value string + SingleQuote bool + NameRange Range +} + +func (ca ConstantAttribute) String() string { + quote := `"` + if ca.SingleQuote { + quote = `'` + } + return ca.Name + `=` + quote + ca.Value + quote +} + +func (ca ConstantAttribute) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, ca.String()) +} + +// noshade={ templ.Bool(...) } +type BoolExpressionAttribute struct { + Name string + Expression Expression + NameRange Range +} + +func (bea BoolExpressionAttribute) String() string { + return bea.Name + `?={ ` + bea.Expression.Value + ` }` +} + +func (bea BoolExpressionAttribute) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, bea.String()) +} + +// href={ ... } +type ExpressionAttribute struct { + Name string + Expression Expression + NameRange Range +} + +func (ea ExpressionAttribute) String() string { + sb := new(strings.Builder) + _ = ea.Write(sb, 0) + return sb.String() +} + +func (ea ExpressionAttribute) formatExpression() (exp []string) { + trimmed := strings.TrimSpace(ea.Expression.Value) + if !strings.Contains(trimmed, "\n") { + formatted, err := format.Source([]byte(trimmed)) + if err != nil { + return []string{trimmed} + } + return []string{string(formatted)} + } + + buf := bytes.NewBufferString("[]any{\n") + buf.WriteString(trimmed) + buf.WriteString("\n}") + + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return []string{trimmed} + } + + // Trim prefix and suffix. + lines := strings.Split(string(formatted), "\n") + if len(lines) < 3 { + return []string{trimmed} + } + + // Return. + return lines[1 : len(lines)-1] +} + +func (ea ExpressionAttribute) Write(w io.Writer, indent int) (err error) { + lines := ea.formatExpression() + if len(lines) == 1 { + return writeIndent(w, indent, ea.Name, `={ `, lines[0], ` }`) + } + + if err = writeIndent(w, indent, ea.Name, "={\n"); err != nil { + return err + } + for _, line := range lines { + if err = writeIndent(w, indent, line, "\n"); err != nil { + return err + } + } + return writeIndent(w, indent, "}") +} + +//
    +type SpreadAttributes struct { + Expression Expression +} + +func (sa SpreadAttributes) String() string { + return `{ ` + sa.Expression.Value + `... }` +} + +func (sa SpreadAttributes) Write(w io.Writer, indent int) error { + return writeIndent(w, indent, sa.String()) +} + +// ") +} + +// Nodes. + +// CallTemplateExpression can be used to create and render a template using data. +// {! Other(p.First, p.Last) } +// or it can be used to render a template parameter. +// {! v } +type CallTemplateExpression struct { + // Expression returns a template to execute. + Expression Expression +} + +func (cte CallTemplateExpression) IsNode() bool { return true } +func (cte CallTemplateExpression) Write(w io.Writer, indent int) error { + // Rewrite to new call syntax + return writeIndent(w, indent, `@`, cte.Expression.Value) +} + +// TemplElementExpression can be used to create and render a template using data. +// @Other(p.First, p.Last) +// or it can be used to render a template parameter. +// @v +type TemplElementExpression struct { + // Expression returns a template to execute. + Expression Expression + // Children returns the elements in a block element. + Children []Node +} + +func (tee TemplElementExpression) ChildNodes() []Node { + return tee.Children +} +func (tee TemplElementExpression) IsNode() bool { return true } +func (tee TemplElementExpression) Write(w io.Writer, indent int) error { + source, err := format.Source([]byte(tee.Expression.Value)) + if err != nil { + source = []byte(tee.Expression.Value) + } + // Indent all lines and re-format, we can then use this to only re-indent lines that gofmt would modify. + reformattedSource, err := format.Source(bytes.ReplaceAll(source, []byte("\n"), []byte("\n\t"))) + if err != nil { + reformattedSource = source + } + sourceLines := bytes.Split(source, []byte("\n")) + reformattedSourceLines := bytes.Split(reformattedSource, []byte("\n")) + for i := range sourceLines { + if i == 0 { + if err := writeIndent(w, indent, "@"+string(sourceLines[i])); err != nil { + return err + } + continue + } + if _, err := io.WriteString(w, "\n"); err != nil { + return err + } + if string(sourceLines[i]) != string(reformattedSourceLines[i]) { + if _, err := w.Write(sourceLines[i]); err != nil { + return err + } + continue + } + if err := writeIndent(w, indent, string(sourceLines[i])); err != nil { + return err + } + } + if len(tee.Children) == 0 { + return nil + } + if _, err = io.WriteString(w, " {\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, tee.Children); err != nil { + return err + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// ChildrenExpression can be used to rended the children of a templ element. +// { children ... } +type ChildrenExpression struct{} + +func (ChildrenExpression) IsNode() bool { return true } +func (ChildrenExpression) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, "{ children... }"); err != nil { + return err + } + return nil +} + +// if p.Type == "test" && p.thing { +// } +type IfExpression struct { + Expression Expression + Then []Node + ElseIfs []ElseIfExpression + Else []Node +} + +type ElseIfExpression struct { + Expression Expression + Then []Node +} + +func (n IfExpression) ChildNodes() []Node { + var nodes []Node + nodes = append(nodes, n.Then...) + nodes = append(nodes, n.Else...) + for _, elseIf := range n.ElseIfs { + nodes = append(nodes, elseIf.Then...) + } + return nodes +} +func (n IfExpression) IsNode() bool { return true } +func (n IfExpression) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, "if ", n.Expression.Value, " {\n"); err != nil { + return err + } + indent++ + if err := writeNodesIndented(w, indent, n.Then); err != nil { + return err + } + indent-- + for _, elseIf := range n.ElseIfs { + if err := writeIndent(w, indent, "} else if ", elseIf.Expression.Value, " {\n"); err != nil { + return err + } + indent++ + if err := writeNodesIndented(w, indent, elseIf.Then); err != nil { + return err + } + indent-- + } + if len(n.Else) > 0 { + if err := writeIndent(w, indent, "} else {\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, n.Else); err != nil { + return err + } + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// switch p.Type { +// case "Something": +// } +type SwitchExpression struct { + Expression Expression + Cases []CaseExpression +} + +func (se SwitchExpression) ChildNodes() []Node { + var nodes []Node + for _, c := range se.Cases { + nodes = append(nodes, c.Children...) + } + return nodes +} +func (se SwitchExpression) IsNode() bool { return true } +func (se SwitchExpression) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, "switch ", se.Expression.Value, " {\n"); err != nil { + return err + } + indent++ + for i := 0; i < len(se.Cases); i++ { + c := se.Cases[i] + if err := writeIndent(w, indent, c.Expression.Value, "\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, c.Children); err != nil { + return err + } + } + indent-- + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// case "Something": +type CaseExpression struct { + Expression Expression + Children []Node +} + +// for i, v := range p.Addresses { +// {! Address(v) } +// } +type ForExpression struct { + Expression Expression + Children []Node +} + +func (fe ForExpression) ChildNodes() []Node { + return fe.Children +} +func (fe ForExpression) IsNode() bool { return true } +func (fe ForExpression) Write(w io.Writer, indent int) error { + if err := writeIndent(w, indent, "for ", fe.Expression.Value, " {\n"); err != nil { + return err + } + if err := writeNodesIndented(w, indent+1, fe.Children); err != nil { + return err + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// GoCode is used within HTML elements, and allows arbitrary go code. +// {{ ... }} +type GoCode struct { + Expression Expression + // TrailingSpace lists what happens after the expression. + TrailingSpace TrailingSpace + Multiline bool +} + +func (gc GoCode) Trailing() TrailingSpace { + return gc.TrailingSpace +} + +func (gc GoCode) IsNode() bool { return true } +func (gc GoCode) Write(w io.Writer, indent int) error { + if isWhitespace(gc.Expression.Value) { + gc.Expression.Value = "" + } + source, err := format.Source([]byte(gc.Expression.Value)) + if err != nil { + source = []byte(gc.Expression.Value) + } + if !gc.Multiline { + return writeIndent(w, indent, `{{ `, string(source), ` }}`) + } + if err := writeIndent(w, indent, "{{"+string(source)+"\n"); err != nil { + return err + } + return writeIndent(w, indent, "}}") +} + +// StringExpression is used within HTML elements, and for style values. +// { ... } +type StringExpression struct { + Expression Expression + // TrailingSpace lists what happens after the expression. + TrailingSpace TrailingSpace +} + +func (se StringExpression) Trailing() TrailingSpace { + return se.TrailingSpace +} + +func (se StringExpression) IsNode() bool { return true } +func (se StringExpression) IsStyleDeclarationValue() bool { return true } +func (se StringExpression) Write(w io.Writer, indent int) error { + if isWhitespace(se.Expression.Value) { + se.Expression.Value = "" + } + return writeIndent(w, indent, `{ `, se.Expression.Value, ` }`) +} + +// ScriptTemplate is a script block. +type ScriptTemplate struct { + Range Range + Name Expression + Parameters Expression + Value string +} + +func (s ScriptTemplate) IsTemplateFileNode() bool { return true } +func (s ScriptTemplate) Write(w io.Writer, indent int) error { + source := formatFunctionArguments(s.Name.Value + "(" + s.Parameters.Value + ")") + if err := writeIndent(w, indent, "script ", string(source), " {\n"); err != nil { + return err + } + if _, err := io.WriteString(w, s.Value); err != nil { + return err + } + if err := writeIndent(w, indent, "}"); err != nil { + return err + } + return nil +} + +// formatFunctionArguments formats the function arguments, if possible. +func formatFunctionArguments(expression string) string { + source := []byte(expression) + formatted, err := format.Source([]byte("func " + expression)) + if err == nil { + formatted = bytes.TrimPrefix(formatted, []byte("func ")) + source = formatted + } + return string(source) +} diff --git a/templ/parser/v2/whitespaceparser.go b/templ/parser/v2/whitespaceparser.go new file mode 100644 index 0000000..c579643 --- /dev/null +++ b/templ/parser/v2/whitespaceparser.go @@ -0,0 +1,12 @@ +package parser + +import "github.com/a-h/parse" + +// Eat any whitespace. +var whitespaceExpression = parse.Func(func(pi *parse.Input) (n Node, ok bool, err error) { + var r Whitespace + if r.Value, ok, err = parse.OptionalWhitespace.Parse(pi); err != nil || !ok { + return + } + return r, len(r.Value) > 0, nil +}) diff --git a/templ/push-tag.sh b/templ/push-tag.sh new file mode 100755 index 0000000..9eedeed --- /dev/null +++ b/templ/push-tag.sh @@ -0,0 +1,14 @@ +#!/bin/sh +if [ `git rev-parse --abbrev-ref HEAD` != "main" ]; then + echo "Error: Not on main branch. Please switch to main branch."; + exit 1; +fi +git pull +if ! git diff --quiet; then + echo "Error: Working directory is not clean. Please commit the changes first."; + exit 1; +fi +export VERSION=`cat .version` +echo Adding git tag with version v${VERSION}; +git tag v${VERSION}; +git push origin v${VERSION}; diff --git a/templ/runtime.go b/templ/runtime.go new file mode 100644 index 0000000..b55459b --- /dev/null +++ b/templ/runtime.go @@ -0,0 +1,638 @@ +package templ + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "html" + "html/template" + "io" + "net/http" + "reflect" + "sort" + "strings" + "sync" + + "github.com/a-h/templ/safehtml" +) + +// Types exposed by all components. + +// Component is the interface that all templates implement. +type Component interface { + // Render the template. + Render(ctx context.Context, w io.Writer) error +} + +// ComponentFunc converts a function that matches the Component interface's +// Render method into a Component. +type ComponentFunc func(ctx context.Context, w io.Writer) error + +// Render the template. +func (cf ComponentFunc) Render(ctx context.Context, w io.Writer) error { + return cf(ctx, w) +} + +// WithNonce sets a CSP nonce on the context and returns it. +func WithNonce(ctx context.Context, nonce string) context.Context { + ctx, v := getContext(ctx) + v.nonce = nonce + return ctx +} + +// GetNonce returns the CSP nonce value set with WithNonce, or an +// empty string if none has been set. +func GetNonce(ctx context.Context) (nonce string) { + if ctx == nil { + return "" + } + _, v := getContext(ctx) + return v.nonce +} + +func WithChildren(ctx context.Context, children Component) context.Context { + ctx, v := getContext(ctx) + v.children = &children + return ctx +} + +func ClearChildren(ctx context.Context) context.Context { + _, v := getContext(ctx) + v.children = nil + return ctx +} + +// NopComponent is a component that doesn't render anything. +var NopComponent = ComponentFunc(func(ctx context.Context, w io.Writer) error { return nil }) + +// GetChildren from the context. +func GetChildren(ctx context.Context) Component { + _, v := getContext(ctx) + if v.children == nil { + return NopComponent + } + return *v.children +} + +// EscapeString escapes HTML text within templates. +func EscapeString(s string) string { + return html.EscapeString(s) +} + +// Bool attribute value. +func Bool(value bool) bool { + return value +} + +// Classes for CSS. +// Supported types are string, ConstantCSSClass, ComponentCSSClass, map[string]bool. +func Classes(classes ...any) CSSClasses { + return CSSClasses(classes) +} + +// CSSClasses is a slice of CSS classes. +type CSSClasses []any + +// String returns the names of all CSS classes. +func (classes CSSClasses) String() string { + if len(classes) == 0 { + return "" + } + cp := newCSSProcessor() + for _, v := range classes { + cp.Add(v) + } + return cp.String() +} + +func newCSSProcessor() *cssProcessor { + return &cssProcessor{ + classNameToEnabled: make(map[string]bool), + } +} + +type cssProcessor struct { + classNameToEnabled map[string]bool + orderedNames []string +} + +func (cp *cssProcessor) Add(item any) { + switch c := item.(type) { + case []string: + for _, className := range c { + cp.AddClassName(className, true) + } + case string: + cp.AddClassName(c, true) + case ConstantCSSClass: + cp.AddClassName(c.ClassName(), true) + case ComponentCSSClass: + cp.AddClassName(c.ClassName(), true) + case map[string]bool: + // In Go, map keys are iterated in a randomized order. + // So the keys in the map must be sorted to produce consistent output. + keys := make([]string, len(c)) + var i int + for key := range c { + keys[i] = key + i++ + } + sort.Strings(keys) + for _, className := range keys { + cp.AddClassName(className, c[className]) + } + case []KeyValue[string, bool]: + for _, kv := range c { + cp.AddClassName(kv.Key, kv.Value) + } + case KeyValue[string, bool]: + cp.AddClassName(c.Key, c.Value) + case []KeyValue[CSSClass, bool]: + for _, kv := range c { + cp.AddClassName(kv.Key.ClassName(), kv.Value) + } + case KeyValue[CSSClass, bool]: + cp.AddClassName(c.Key.ClassName(), c.Value) + case CSSClasses: + for _, item := range c { + cp.Add(item) + } + case []CSSClass: + for _, item := range c { + cp.Add(item) + } + case func() CSSClass: + cp.AddClassName(c().ClassName(), true) + default: + cp.AddClassName(unknownTypeClassName, true) + } +} + +func (cp *cssProcessor) AddClassName(className string, enabled bool) { + cp.classNameToEnabled[className] = enabled + cp.orderedNames = append(cp.orderedNames, className) +} + +func (cp *cssProcessor) String() string { + // Order the outputs according to how they were input, and remove disabled names. + rendered := make(map[string]any, len(cp.classNameToEnabled)) + var names []string + for _, name := range cp.orderedNames { + if enabled := cp.classNameToEnabled[name]; !enabled { + continue + } + if _, hasBeenRendered := rendered[name]; hasBeenRendered { + continue + } + names = append(names, name) + rendered[name] = struct{}{} + } + + return strings.Join(names, " ") +} + +// KeyValue is a key and value pair. +type KeyValue[TKey comparable, TValue any] struct { + Key TKey `json:"name"` + Value TValue `json:"value"` +} + +// KV creates a new key/value pair from the input key and value. +func KV[TKey comparable, TValue any](key TKey, value TValue) KeyValue[TKey, TValue] { + return KeyValue[TKey, TValue]{ + Key: key, + Value: value, + } +} + +const unknownTypeClassName = "--templ-css-class-unknown-type" + +// Class returns a CSS class name. +// Deprecated: use a string instead. +func Class(name string) CSSClass { + return SafeClass(name) +} + +// SafeClass bypasses CSS class name validation. +// Deprecated: use a string instead. +func SafeClass(name string) CSSClass { + return ConstantCSSClass(name) +} + +// CSSClass provides a class name. +type CSSClass interface { + ClassName() string +} + +// ConstantCSSClass is a string constant of a CSS class name. +// Deprecated: use a string instead. +type ConstantCSSClass string + +// ClassName of the CSS class. +func (css ConstantCSSClass) ClassName() string { + return string(css) +} + +// ComponentCSSClass is a templ.CSS +type ComponentCSSClass struct { + // ID of the class, will be autogenerated. + ID string + // Definition of the CSS. + Class SafeCSS +} + +// ClassName of the CSS class. +func (css ComponentCSSClass) ClassName() string { + return css.ID +} + +// CSSID calculates an ID. +func CSSID(name string, css string) string { + sum := sha256.Sum256([]byte(css)) + hs := hex.EncodeToString(sum[:])[0:8] // NOTE: See issue #978. Minimum recommended hs length is 6. + // Benchmarking showed this was fastest, and with fewest allocations (1). + // Using strings.Builder (2 allocs). + // Using fmt.Sprintf (3 allocs). + return name + "_" + hs +} + +// NewCSSMiddleware creates HTTP middleware that renders a global stylesheet of ComponentCSSClass +// CSS if the request path matches, or updates the HTTP context to ensure that any handlers that +// use templ.Components skip rendering `); err != nil { + return err + } + } + return nil +} + +func renderCSSItemsToBuilder(sb *strings.Builder, v *contextValue, classes ...any) { + for _, c := range classes { + switch ccc := c.(type) { + case ComponentCSSClass: + if !v.hasClassBeenRendered(ccc.ID) { + sb.WriteString(string(ccc.Class)) + v.addClass(ccc.ID) + } + case KeyValue[ComponentCSSClass, bool]: + if !ccc.Value { + continue + } + renderCSSItemsToBuilder(sb, v, ccc.Key) + case KeyValue[CSSClass, bool]: + if !ccc.Value { + continue + } + renderCSSItemsToBuilder(sb, v, ccc.Key) + case CSSClasses: + renderCSSItemsToBuilder(sb, v, ccc...) + case []CSSClass: + for _, item := range ccc { + renderCSSItemsToBuilder(sb, v, item) + } + case func() CSSClass: + renderCSSItemsToBuilder(sb, v, ccc()) + case []string: + // Skip. These are class names, not CSS classes. + case string: + // Skip. This is a class name, not a CSS class. + case ConstantCSSClass: + // Skip. This is a class name, not a CSS class. + case CSSClass: + // Skip. This is a class name, not a CSS class. + case map[string]bool: + // Skip. These are class names, not CSS classes. + case KeyValue[string, bool]: + // Skip. These are class names, not CSS classes. + case []KeyValue[string, bool]: + // Skip. These are class names, not CSS classes. + case KeyValue[ConstantCSSClass, bool]: + // Skip. These are class names, not CSS classes. + case []KeyValue[ConstantCSSClass, bool]: + // Skip. These are class names, not CSS classes. + } + } +} + +// SafeCSS is CSS that has been sanitized. +type SafeCSS string + +type SafeCSSProperty string + +var safeCSSPropertyType = reflect.TypeOf(SafeCSSProperty("")) + +// SanitizeCSS sanitizes CSS properties to ensure that they are safe. +func SanitizeCSS[T ~string](property string, value T) SafeCSS { + if reflect.TypeOf(value) == safeCSSPropertyType { + return SafeCSS(safehtml.SanitizeCSSProperty(property) + ":" + string(value) + ";") + } + p, v := safehtml.SanitizeCSS(property, string(value)) + return SafeCSS(p + ":" + v + ";") +} + +// Attributes is an alias to map[string]any made for spread attributes. +type Attributes map[string]any + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]any) (keys []string) { + keys = make([]string, len(m)) + var i int + for k := range m { + keys[i] = k + i++ + } + sort.Strings(keys) + return keys +} + +func writeStrings(w io.Writer, ss ...string) (err error) { + for _, s := range ss { + if _, err = io.WriteString(w, s); err != nil { + return err + } + } + return nil +} + +func RenderAttributes(ctx context.Context, w io.Writer, attributes Attributes) (err error) { + for _, key := range sortedKeys(attributes) { + value := attributes[key] + switch value := value.(type) { + case string: + if err = writeStrings(w, ` `, EscapeString(key), `="`, EscapeString(value), `"`); err != nil { + return err + } + case *string: + if value != nil { + if err = writeStrings(w, ` `, EscapeString(key), `="`, EscapeString(*value), `"`); err != nil { + return err + } + } + case bool: + if value { + if err = writeStrings(w, ` `, EscapeString(key)); err != nil { + return err + } + } + case *bool: + if value != nil && *value { + if err = writeStrings(w, ` `, EscapeString(key)); err != nil { + return err + } + } + case KeyValue[string, bool]: + if value.Value { + if err = writeStrings(w, ` `, EscapeString(key), `="`, EscapeString(value.Key), `"`); err != nil { + return err + } + } + case KeyValue[bool, bool]: + if value.Value && value.Key { + if err = writeStrings(w, ` `, EscapeString(key)); err != nil { + return err + } + } + case func() bool: + if value() { + if err = writeStrings(w, ` `, EscapeString(key)); err != nil { + return err + } + } + } + } + return nil +} + +// Context. + +type contextKeyType int + +const contextKey = contextKeyType(0) + +type contextValue struct { + ss map[string]struct{} + onceHandles map[*OnceHandle]struct{} + children *Component + nonce string +} + +func (v *contextValue) setHasBeenRendered(h *OnceHandle) { + if v.onceHandles == nil { + v.onceHandles = map[*OnceHandle]struct{}{} + } + v.onceHandles[h] = struct{}{} +} + +func (v *contextValue) getHasBeenRendered(h *OnceHandle) (ok bool) { + if v.onceHandles == nil { + v.onceHandles = map[*OnceHandle]struct{}{} + } + _, ok = v.onceHandles[h] + return +} + +func (v *contextValue) addScript(s string) { + if v.ss == nil { + v.ss = map[string]struct{}{} + } + v.ss["script_"+s] = struct{}{} +} + +func (v *contextValue) hasScriptBeenRendered(s string) (ok bool) { + if v.ss == nil { + v.ss = map[string]struct{}{} + } + _, ok = v.ss["script_"+s] + return +} + +func (v *contextValue) addClass(s string) { + if v.ss == nil { + v.ss = map[string]struct{}{} + } + v.ss["class_"+s] = struct{}{} +} + +func (v *contextValue) hasClassBeenRendered(s string) (ok bool) { + if v.ss == nil { + v.ss = map[string]struct{}{} + } + _, ok = v.ss["class_"+s] + return +} + +// InitializeContext initializes context used to store internal state used during rendering. +func InitializeContext(ctx context.Context) context.Context { + if _, ok := ctx.Value(contextKey).(*contextValue); ok { + return ctx + } + v := &contextValue{} + ctx = context.WithValue(ctx, contextKey, v) + return ctx +} + +func getContext(ctx context.Context) (context.Context, *contextValue) { + v, ok := ctx.Value(contextKey).(*contextValue) + if !ok { + ctx = InitializeContext(ctx) + v = ctx.Value(contextKey).(*contextValue) + } + return ctx, v +} + +var bufferPool = sync.Pool{ + New: func() any { + return new(bytes.Buffer) + }, +} + +func GetBuffer() *bytes.Buffer { + return bufferPool.Get().(*bytes.Buffer) +} + +func ReleaseBuffer(b *bytes.Buffer) { + b.Reset() + bufferPool.Put(b) +} + +// JoinStringErrs joins an optional list of errors. +func JoinStringErrs(s string, errs ...error) (string, error) { + return s, errors.Join(errs...) +} + +// Error returned during template rendering. +type Error struct { + Err error + // FileName of the template file. + FileName string + // Line index of the error. + Line int + // Col index of the error. + Col int +} + +func (e Error) Error() string { + if e.FileName == "" { + e.FileName = "templ" + } + return fmt.Sprintf("%s: error at line %d, col %d: %v", e.FileName, e.Line, e.Col, e.Err) +} + +func (e Error) Unwrap() error { + return e.Err +} + +// Raw renders the input HTML to the output without applying HTML escaping. +// +// Use of this component presents a security risk - the HTML should come from +// a trusted source, because it will be included as-is in the output. +func Raw[T ~string](html T, errs ...error) Component { + return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + if err = errors.Join(errs...); err != nil { + return err + } + _, err = io.WriteString(w, string(html)) + return err + }) +} + +// FromGoHTML creates a templ Component from a Go html/template template. +func FromGoHTML(t *template.Template, data any) Component { + return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + return t.Execute(w, data) + }) +} + +// ToGoHTML renders the component to a Go html/template template.HTML string. +func ToGoHTML(ctx context.Context, c Component) (s template.HTML, err error) { + b := GetBuffer() + defer ReleaseBuffer(b) + if err = c.Render(ctx, b); err != nil { + return + } + s = template.HTML(b.String()) + return +} diff --git a/templ/runtime/buffer.go b/templ/runtime/buffer.go new file mode 100644 index 0000000..63e4acd --- /dev/null +++ b/templ/runtime/buffer.go @@ -0,0 +1,62 @@ +package runtime + +import ( + "bufio" + "io" + "net/http" +) + +// DefaultBufferSize is the default size of buffers. It is set to 4KB by default, which is the +// same as the default buffer size of bufio.Writer. +var DefaultBufferSize = 4 * 1024 // 4KB + +// Buffer is a wrapper around bufio.Writer that enables flushing and closing of +// the underlying writer. +type Buffer struct { + Underlying io.Writer + b *bufio.Writer +} + +// Write the contents of p into the buffer. +func (b *Buffer) Write(p []byte) (n int, err error) { + return b.b.Write(p) +} + +// Flush writes any buffered data to the underlying io.Writer and +// calls the Flush method of the underlying http.Flusher if it implements it. +func (b *Buffer) Flush() error { + if err := b.b.Flush(); err != nil { + return err + } + if f, ok := b.Underlying.(http.Flusher); ok { + f.Flush() + } + return nil +} + +// Close closes the buffer and the underlying io.Writer if it implements io.Closer. +func (b *Buffer) Close() error { + if c, ok := b.Underlying.(io.Closer); ok { + return c.Close() + } + return nil +} + +// Reset sets the underlying io.Writer to w and resets the buffer. +func (b *Buffer) Reset(w io.Writer) { + if b.b == nil { + b.b = bufio.NewWriterSize(b, DefaultBufferSize) + } + b.Underlying = w + b.b.Reset(w) +} + +// Size returns the size of the underlying buffer in bytes. +func (b *Buffer) Size() int { + return b.b.Size() +} + +// WriteString writes the contents of s into the buffer. +func (b *Buffer) WriteString(s string) (n int, err error) { + return b.b.WriteString(s) +} diff --git a/templ/runtime/buffer_test.go b/templ/runtime/buffer_test.go new file mode 100644 index 0000000..920f659 --- /dev/null +++ b/templ/runtime/buffer_test.go @@ -0,0 +1,79 @@ +package runtime + +import ( + "errors" + "net/http/httptest" + "testing" +) + +var wasClosed bool + +type closable struct { + *httptest.ResponseRecorder +} + +func (c *closable) Close() error { + wasClosed = true + return nil +} + +func TestBuffer(t *testing.T) { + underlying := httptest.NewRecorder() + w, _ := GetBuffer(&closable{underlying}) + t.Run("can write to a buffer", func(t *testing.T) { + if _, err := w.Write([]byte("A")); err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("can write a string to a buffer", func(t *testing.T) { + if _, err := w.WriteString("A"); err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("can flush a buffer", func(t *testing.T) { + if err := w.Flush(); err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("can close a buffer", func(t *testing.T) { + if err := w.Close(); err != nil { + t.Errorf("unexpected error: %v", err) + } + if !wasClosed { + t.Error("expected the underlying writer to be closed") + } + }) + t.Run("can get the size of a buffer", func(t *testing.T) { + if w.Size() != DefaultBufferSize { + t.Errorf("expected %d, got %d", DefaultBufferSize, w.Size()) + } + }) + t.Run("can reset a buffer", func(t *testing.T) { + w.Reset(underlying) + }) + if underlying.Body.String() != "AA" { + t.Errorf("expected %q, got %q", "AA", underlying.Body.String()) + } +} + +type failStream struct { +} + +var errTest = errors.New("test error") + +func (f *failStream) Write(p []byte) (n int, err error) { + return 0, errTest +} + +func (f *failStream) Close() error { + return errTest +} + +func TestBufferErrors(t *testing.T) { + w, _ := GetBuffer(&failStream{}) + t.Run("close errors are returned", func(t *testing.T) { + if err := w.Close(); err != errTest { + t.Errorf("expected %v, got %v", errTest, err) + } + }) +} diff --git a/templ/runtime/bufferpool.go b/templ/runtime/bufferpool.go new file mode 100644 index 0000000..ca2a131 --- /dev/null +++ b/templ/runtime/bufferpool.go @@ -0,0 +1,38 @@ +package runtime + +import ( + "io" + "sync" +) + +var bufferPool = sync.Pool{ + New: func() any { + return new(Buffer) + }, +} + +// GetBuffer creates and returns a new buffer if the writer is not already a buffer, +// or returns the existing buffer if it is. +func GetBuffer(w io.Writer) (b *Buffer, existing bool) { + if w == nil { + return nil, false + } + b, ok := w.(*Buffer) + if ok { + return b, true + } + b = bufferPool.Get().(*Buffer) + b.Reset(w) + return b, false +} + +// ReleaseBuffer flushes the buffer and returns it to the pool. +func ReleaseBuffer(w io.Writer) (err error) { + b, ok := w.(*Buffer) + if !ok { + return nil + } + err = b.Flush() + bufferPool.Put(b) + return err +} diff --git a/templ/runtime/bufferpool_test.go b/templ/runtime/bufferpool_test.go new file mode 100644 index 0000000..1724825 --- /dev/null +++ b/templ/runtime/bufferpool_test.go @@ -0,0 +1,59 @@ +package runtime + +import ( + "bytes" + "testing" +) + +func TestBufferPool(t *testing.T) { + t.Run("can get a buffer from the pool", func(t *testing.T) { + w, existing := GetBuffer(new(bytes.Buffer)) + if w == nil { + t.Error("expected a buffer, got nil") + } + if existing { + t.Error("expected a new buffer, got an existing buffer") + } + err := ReleaseBuffer(w) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("can get an existing buffer from the pool", func(t *testing.T) { + w, existing := GetBuffer(new(bytes.Buffer)) + if w == nil { + t.Error("expected a buffer, got nil") + } + if existing { + t.Error("expected a new buffer, got an existing buffer") + } + + w, existing = GetBuffer(w) + if w == nil { + t.Error("expected a buffer, got nil") + } + if !existing { + t.Error("expected an existing buffer, got a new buffer") + } + + err := ReleaseBuffer(w) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("can release any writer without error", func(t *testing.T) { + err := ReleaseBuffer(new(bytes.Buffer)) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + }) + t.Run("attempting to buffer a nil writer returns nil", func(t *testing.T) { + w, existing := GetBuffer(nil) + if w != nil { + t.Error("expected nil, got a buffer") + } + if existing { + t.Error("expected nil, got an existing buffer") + } + }) +} diff --git a/templ/runtime/builder.go b/templ/runtime/builder.go new file mode 100644 index 0000000..0f4c9d4 --- /dev/null +++ b/templ/runtime/builder.go @@ -0,0 +1,8 @@ +package runtime + +import "strings" + +// GetBuilder returns a strings.Builder. +func GetBuilder() (sb strings.Builder) { + return sb +} diff --git a/templ/runtime/builder_test.go b/templ/runtime/builder_test.go new file mode 100644 index 0000000..f764997 --- /dev/null +++ b/templ/runtime/builder_test.go @@ -0,0 +1,11 @@ +package runtime + +import "testing" + +func TestGetBuilder(t *testing.T) { + sb := GetBuilder() + sb.WriteString("test") + if sb.String() != "test" { + t.Errorf("expected \"test\", got %q", sb.String()) + } +} diff --git a/templ/runtime/runtime.go b/templ/runtime/runtime.go new file mode 100644 index 0000000..aaa4a2c --- /dev/null +++ b/templ/runtime/runtime.go @@ -0,0 +1,21 @@ +package runtime + +import ( + "context" + "io" + + "github.com/a-h/templ" +) + +// GeneratedComponentInput is used to avoid generated code needing to import the `context` and `io` packages. +type GeneratedComponentInput struct { + Context context.Context + Writer io.Writer +} + +// GeneratedTemplate is used to avoid generated code needing to import the `context` and `io` packages. +func GeneratedTemplate(f func(GeneratedComponentInput) error) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + return f(GeneratedComponentInput{ctx, w}) + }) +} diff --git a/templ/runtime/runtime_test.go b/templ/runtime/runtime_test.go new file mode 100644 index 0000000..d5bb070 --- /dev/null +++ b/templ/runtime/runtime_test.go @@ -0,0 +1,22 @@ +package runtime + +import ( + "context" + "strings" + "testing" +) + +func TestGeneratedTemplate(t *testing.T) { + f := func(input GeneratedComponentInput) error { + _, err := input.Writer.Write([]byte("Hello, World!")) + return err + } + sb := new(strings.Builder) + err := GeneratedTemplate(f).Render(context.Background(), sb) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if sb.String() != "Hello, World!" { + t.Errorf("expected \"Hello, World!\", got %q", sb.String()) + } +} diff --git a/templ/runtime/styleattribute.go b/templ/runtime/styleattribute.go new file mode 100644 index 0000000..c6e61ec --- /dev/null +++ b/templ/runtime/styleattribute.go @@ -0,0 +1,217 @@ +package runtime + +import ( + "errors" + "fmt" + "html" + "maps" + "reflect" + "slices" + "strings" + + "github.com/a-h/templ" + "github.com/a-h/templ/safehtml" +) + +// SanitizeStyleAttributeValues renders a style attribute value. +// The supported types are: +// - string +// - templ.SafeCSS +// - map[string]string +// - map[string]templ.SafeCSSProperty +// - templ.KeyValue[string, string] - A map of key/values where the key is the CSS property name and the value is the CSS property value. +// - templ.KeyValue[string, templ.SafeCSSProperty] - A map of key/values where the key is the CSS property name and the value is the CSS property value. +// - templ.KeyValue[string, bool] - The bool determines whether the value should be included. +// - templ.KeyValue[templ.SafeCSS, bool] - The bool determines whether the value should be included. +// - func() (anyOfTheAboveTypes) +// - func() (anyOfTheAboveTypes, error) +// - []anyOfTheAboveTypes +// +// In the above, templ.SafeCSS and templ.SafeCSSProperty are types that are used to indicate that the value is safe to render as CSS without sanitization. +// All other types are sanitized before rendering. +// +// If an error is returned by any function, or a non-nil error is included in the input, the error is returned. +func SanitizeStyleAttributeValues(values ...any) (string, error) { + if err := getJoinedErrorsFromValues(values...); err != nil { + return "", err + } + sb := new(strings.Builder) + for _, v := range values { + if v == nil { + continue + } + if err := sanitizeStyleAttributeValue(sb, v); err != nil { + return "", err + } + } + return sb.String(), nil +} + +func sanitizeStyleAttributeValue(sb *strings.Builder, v any) error { + // Process concrete types. + switch v := v.(type) { + case string: + return processString(sb, v) + + case templ.SafeCSS: + return processSafeCSS(sb, v) + + case map[string]string: + return processStringMap(sb, v) + + case map[string]templ.SafeCSSProperty: + return processSafeCSSPropertyMap(sb, v) + + case templ.KeyValue[string, string]: + return processStringKV(sb, v) + + case templ.KeyValue[string, bool]: + if v.Value { + return processString(sb, v.Key) + } + return nil + + case templ.KeyValue[templ.SafeCSS, bool]: + if v.Value { + return processSafeCSS(sb, v.Key) + } + return nil + } + + // Fall back to reflection. + + // Handle functions first using reflection. + if handled, err := handleFuncWithReflection(sb, v); handled { + return err + } + + // Handle slices using reflection before concrete types. + if handled, err := handleSliceWithReflection(sb, v); handled { + return err + } + + _, err := sb.WriteString(TemplUnsupportedStyleAttributeValue) + return err +} + +func processSafeCSS(sb *strings.Builder, v templ.SafeCSS) error { + if v == "" { + return nil + } + sb.WriteString(html.EscapeString(string(v))) + if !strings.HasSuffix(string(v), ";") { + sb.WriteRune(';') + } + return nil +} + +func processString(sb *strings.Builder, v string) error { + if v == "" { + return nil + } + sanitized := strings.TrimSpace(safehtml.SanitizeStyleValue(v)) + sb.WriteString(html.EscapeString(sanitized)) + if !strings.HasSuffix(sanitized, ";") { + sb.WriteRune(';') + } + return nil +} + +var ErrInvalidStyleAttributeFunctionSignature = errors.New("invalid function signature, should be in the form func() (string, error)") + +// handleFuncWithReflection handles functions using reflection. +func handleFuncWithReflection(sb *strings.Builder, v any) (bool, error) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Func { + return false, nil + } + + t := rv.Type() + if t.NumIn() != 0 || (t.NumOut() != 1 && t.NumOut() != 2) { + return false, ErrInvalidStyleAttributeFunctionSignature + } + + // Check the types of the return values + if t.NumOut() == 2 { + // Ensure the second return value is of type `error` + secondReturnType := t.Out(1) + if !secondReturnType.Implements(reflect.TypeOf((*error)(nil)).Elem()) { + return false, fmt.Errorf("second return value must be of type error, got %v", secondReturnType) + } + } + + results := rv.Call(nil) + + if t.NumOut() == 2 { + // Check if the second return value is an error + if errVal := results[1].Interface(); errVal != nil { + if err, ok := errVal.(error); ok && err != nil { + return true, err + } + } + } + + return true, sanitizeStyleAttributeValue(sb, results[0].Interface()) +} + +// handleSliceWithReflection handles slices using reflection. +func handleSliceWithReflection(sb *strings.Builder, v any) (bool, error) { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Slice { + return false, nil + } + for i := 0; i < rv.Len(); i++ { + elem := rv.Index(i).Interface() + if err := sanitizeStyleAttributeValue(sb, elem); err != nil { + return true, err + } + } + return true, nil +} + +// processStringMap processes a map[string]string. +func processStringMap(sb *strings.Builder, m map[string]string) error { + for _, name := range slices.Sorted(maps.Keys(m)) { + name, value := safehtml.SanitizeCSS(name, m[name]) + sb.WriteString(html.EscapeString(name)) + sb.WriteRune(':') + sb.WriteString(html.EscapeString(value)) + sb.WriteRune(';') + } + return nil +} + +// processSafeCSSPropertyMap processes a map[string]templ.SafeCSSProperty. +func processSafeCSSPropertyMap(sb *strings.Builder, m map[string]templ.SafeCSSProperty) error { + for _, name := range slices.Sorted(maps.Keys(m)) { + sb.WriteString(html.EscapeString(safehtml.SanitizeCSSProperty(name))) + sb.WriteRune(':') + sb.WriteString(html.EscapeString(string(m[name]))) + sb.WriteRune(';') + } + return nil +} + +// processStringKV processes a templ.KeyValue[string, string]. +func processStringKV(sb *strings.Builder, kv templ.KeyValue[string, string]) error { + name, value := safehtml.SanitizeCSS(kv.Key, kv.Value) + sb.WriteString(html.EscapeString(name)) + sb.WriteRune(':') + sb.WriteString(html.EscapeString(value)) + sb.WriteRune(';') + return nil +} + +// getJoinedErrorsFromValues collects and joins errors from the input values. +func getJoinedErrorsFromValues(values ...any) error { + var errs []error + for _, v := range values { + if err, ok := v.(error); ok { + errs = append(errs, err) + } + } + return errors.Join(errs...) +} + +// TemplUnsupportedStyleAttributeValue is the default value returned for unsupported types. +var TemplUnsupportedStyleAttributeValue = "zTemplUnsupportedStyleAttributeValue:Invalid;" diff --git a/templ/runtime/styleattribute_test.go b/templ/runtime/styleattribute_test.go new file mode 100644 index 0000000..4b32cc3 --- /dev/null +++ b/templ/runtime/styleattribute_test.go @@ -0,0 +1,333 @@ +package runtime + +import ( + "errors" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +var ( + err1 = errors.New("error 1") + err2 = errors.New("error 2") +) + +func TestSanitizeStyleAttribute(t *testing.T) { + tests := []struct { + name string + input []any + expected string + expectedErr error + }{ + { + name: "errors are returned", + input: []any{err1}, + expectedErr: err1, + }, + { + name: "multiple errors are joined and returned", + input: []any{err1, err2}, + expectedErr: errors.Join(err1, err2), + }, + { + name: "functions that return errors return the error", + input: []any{ + "color:red", + func() (string, error) { return "", err1 }, + }, + expectedErr: err1, + }, + + // string + { + name: "strings: are allowed", + input: []any{"color:red;background-color:blue;"}, + expected: "color:red;background-color:blue;", + }, + { + name: "strings: have semi-colons appended if missing", + input: []any{"color:red;background-color:blue"}, + expected: "color:red;background-color:blue;", + }, + { + name: "strings: empty strings are elided", + input: []any{""}, + expected: "", + }, + { + name: "strings: are sanitized", + input: []any{""}, + expected: `\00003C/style>\00003Cscript>alert('xss')\00003C/script>;`, + }, + + // templ.SafeCSS + { + name: "SafeCSS: is allowed", + input: []any{templ.SafeCSS("color:red;background-color:blue;")}, + expected: "color:red;background-color:blue;", + }, + { + name: "SafeCSS: have semi-colons appended if missing", + input: []any{templ.SafeCSS("color:red;background-color:blue")}, + expected: "color:red;background-color:blue;", + }, + { + name: "SafeCSS: empty strings are elided", + input: []any{templ.SafeCSS("")}, + expected: "", + }, + { + name: "SafeCSS: is escaped, but not sanitized", + input: []any{templ.SafeCSS("")}, + expected: `</style>;`, + }, + + // map[string]string + { + name: "map[string]string: is allowed", + input: []any{map[string]string{"color": "red", "background-color": "blue"}}, + expected: "background-color:blue;color:red;", + }, + { + name: "map[string]string: keys are sorted", + input: []any{map[string]string{"z-index": "1", "color": "red", "background-color": "blue"}}, + expected: "background-color:blue;color:red;z-index:1;", + }, + { + name: "map[string]string: empty names are invalid", + input: []any{map[string]string{"": "red", "background-color": "blue"}}, + expected: "zTemplUnsafeCSSPropertyName:zTemplUnsafeCSSPropertyValue;background-color:blue;", + }, + { + name: "map[string]string: keys and values are sanitized", + input: []any{map[string]string{"color": "", "background-color": "blue"}}, + expected: "background-color:blue;color:zTemplUnsafeCSSPropertyValue;", + }, + + // map[string]templ.SafeCSSProperty + { + name: "map[string]templ.SafeCSSProperty: is allowed", + input: []any{map[string]templ.SafeCSSProperty{"color": "red", "background-color": "blue"}}, + expected: "background-color:blue;color:red;", + }, + { + name: "map[string]templ.SafeCSSProperty: keys are sorted", + input: []any{map[string]templ.SafeCSSProperty{"z-index": "1", "color": "red", "background-color": "blue"}}, + expected: "background-color:blue;color:red;z-index:1;", + }, + { + name: "map[string]templ.SafeCSSProperty: empty names are invalid", + input: []any{map[string]templ.SafeCSSProperty{"": "red", "background-color": "blue"}}, + expected: "zTemplUnsafeCSSPropertyName:red;background-color:blue;", + }, + { + name: "map[string]templ.SafeCSSProperty: keys are sanitized, but not values", + input: []any{map[string]templ.SafeCSSProperty{"color": "", "": "blue"}}, + expected: "zTemplUnsafeCSSPropertyName:blue;color:</style>;", + }, + + // templ.KeyValue[string, string] + { + name: "KeyValue[string, string]: is allowed", + input: []any{templ.KV("color", "red"), templ.KV("background-color", "blue")}, + expected: "color:red;background-color:blue;", + }, + { + name: "KeyValue[string, string]: keys and values are sanitized", + input: []any{templ.KV("color", ""), templ.KV("", "blue")}, + expected: "color:zTemplUnsafeCSSPropertyValue;zTemplUnsafeCSSPropertyName:zTemplUnsafeCSSPropertyValue;", + }, + { + name: "KeyValue[string, string]: empty names are invalid", + input: []any{templ.KV("", "red"), templ.KV("background-color", "blue")}, + expected: "zTemplUnsafeCSSPropertyName:zTemplUnsafeCSSPropertyValue;background-color:blue;", + }, + + // templ.KeyValue[string, templ.SafeCSSProperty] + { + name: "KeyValue[string, templ.SafeCSSProperty]: is allowed", + input: []any{templ.KV("color", "red"), templ.KV("background-color", "blue")}, + expected: "color:red;background-color:blue;", + }, + { + name: "KeyValue[string, templ.SafeCSSProperty]: keys are sanitized, but not values", + input: []any{templ.KV("color", ""), templ.KV("", "blue")}, + expected: "color:zTemplUnsafeCSSPropertyValue;zTemplUnsafeCSSPropertyName:zTemplUnsafeCSSPropertyValue;", + }, + { + name: "KeyValue[string, templ.SafeCSSProperty]: empty names are invalid", + input: []any{templ.KV("", "red"), templ.KV("background-color", "blue")}, + expected: "zTemplUnsafeCSSPropertyName:zTemplUnsafeCSSPropertyValue;background-color:blue;", + }, + + // templ.KeyValue[string, bool] + { + name: "KeyValue[string, bool]: is allowed", + input: []any{templ.KV("color:red", true), templ.KV("background-color:blue", true), templ.KV("color:blue", false)}, + expected: "color:red;background-color:blue;", + }, + { + name: "KeyValue[string, bool]: false values are elided", + input: []any{templ.KV("color:red", false), templ.KV("background-color:blue", true)}, + expected: "background-color:blue;", + }, + { + name: "KeyValue[string, bool]: keys are sanitized as per strings", + input: []any{templ.KV("", true), templ.KV("background-color:blue", true)}, + expected: "\\00003C/style>;background-color:blue;", + }, + + // templ.KeyValue[templ.SafeCSS, bool] + { + name: "KeyValue[templ.SafeCSS, bool]: is allowed", + input: []any{templ.KV(templ.SafeCSS("color:red"), true), templ.KV(templ.SafeCSS("background-color:blue"), true), templ.KV(templ.SafeCSS("color:blue"), false)}, + expected: "color:red;background-color:blue;", + }, + { + name: "KeyValue[templ.SafeCSS, bool]: false values are elided", + input: []any{templ.KV(templ.SafeCSS("color:red"), false), templ.KV(templ.SafeCSS("background-color:blue"), true)}, + expected: "background-color:blue;", + }, + { + name: "KeyValue[templ.SafeCSS, bool]: keys are not sanitized", + input: []any{templ.KV(templ.SafeCSS(""), true), templ.KV(templ.SafeCSS("background-color:blue"), true)}, + expected: "</style>;background-color:blue;", + }, + + // Functions. + { + name: "func: string", + input: []any{ + func() string { return "color:red" }, + }, + expected: `color:red;`, + }, + { + name: "func: string, error - success", + input: []any{ + func() (string, error) { return "color:blue", nil }, + }, + expected: `color:blue;`, + }, + { + name: "func: string, error - error", + input: []any{ + func() (string, error) { return "", err1 }, + }, + expectedErr: err1, + }, + { + name: "func: invalid signature", + input: []any{ + func() (string, string) { return "color:blue", "color:blue" }, + }, + expected: TemplUnsupportedStyleAttributeValue, + }, + { + name: "func: only one or two return values are allowed", + input: []any{ + func() (string, string, string) { return "color:blue", "color:blue", "color:blue" }, + }, + expected: TemplUnsupportedStyleAttributeValue, + }, + + // Slices. + { + name: "slices: mixed types are allowed", + input: []any{ + []any{ + "color:red", + templ.KV("text-decoration: underline", true), + map[string]string{"background": "blue"}, + }, + }, + expected: `color:red;text-decoration: underline;background:blue;`, + }, + { + name: "slices: nested slices are allowed", + input: []any{ + []any{ + []string{"color:red", "font-size:12px"}, + []templ.SafeCSS{"margin:0", "padding:0"}, + }, + }, + expected: `color:red;font-size:12px;margin:0;padding:0;`, + }, + + // Edge cases. + { + name: "edge: nil input", + input: nil, + expected: "", + }, + { + name: "edge: empty input", + input: []any{}, + expected: "", + }, + { + name: "edge: unsupported type", + input: []any{42}, + expected: TemplUnsupportedStyleAttributeValue, + }, + { + name: "edge: nil input", + input: []any{nil}, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := SanitizeStyleAttributeValues(tt.input...) + + if tt.expectedErr != nil { + if err == nil { + t.Fatal("expected error but got nil") + } + if diff := cmp.Diff(tt.expectedErr.Error(), err.Error()); diff != "" { + t.Errorf("error mismatch (-want +got):\n%s", diff) + } + return + } + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if diff := cmp.Diff(tt.expected, actual); diff != "" { + t.Errorf("result mismatch (-want +got):\n%s", diff) + t.Logf("Actual result: %q", actual) + } + }) + } +} + +func benchmarkSanitizeAttributeValues(b *testing.B, input ...any) { + for n := 0; n < b.N; n++ { + if _, err := SanitizeStyleAttributeValues(input...); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkSanitizeAttributeValuesErr(b *testing.B) { benchmarkSanitizeAttributeValues(b, err1) } +func BenchmarkSanitizeAttributeValuesString(b *testing.B) { + benchmarkSanitizeAttributeValues(b, "color:red;background-color:blue;") +} +func BenchmarkSanitizeAttributeValuesStringSanitized(b *testing.B) { + benchmarkSanitizeAttributeValues(b, "") +} +func BenchmarkSanitizeAttributeValuesSafeCSS(b *testing.B) { + benchmarkSanitizeAttributeValues(b, templ.SafeCSS("color:red;background-color:blue;")) +} +func BenchmarkSanitizeAttributeValuesMap(b *testing.B) { + benchmarkSanitizeAttributeValues(b, map[string]string{"color": "red", "background-color": "blue"}) +} +func BenchmarkSanitizeAttributeValuesKV(b *testing.B) { + benchmarkSanitizeAttributeValues(b, templ.KV("color", "red"), templ.KV("background-color", "blue")) +} +func BenchmarkSanitizeAttributeValuesFunc(b *testing.B) { + benchmarkSanitizeAttributeValues(b, func() string { return "color:red" }) +} diff --git a/templ/runtime/watchmode.go b/templ/runtime/watchmode.go new file mode 100644 index 0000000..26e3c06 --- /dev/null +++ b/templ/runtime/watchmode.go @@ -0,0 +1,104 @@ +package runtime + +import ( + "errors" + "fmt" + "io" + "os" + "runtime" + "strconv" + "strings" + "sync" + "time" +) + +var developmentMode = os.Getenv("TEMPL_DEV_MODE") == "true" + +// WriteString writes the string to the writer. If development mode is enabled +// s is replaced with the string at the index in the _templ.txt file. +func WriteString(w io.Writer, index int, s string) (err error) { + if developmentMode { + _, path, _, _ := runtime.Caller(1) + if !strings.HasSuffix(path, "_templ.go") { + return errors.New("templ: attempt to use WriteString from a non templ file") + } + txtFilePath := strings.Replace(path, "_templ.go", "_templ.txt", 1) + + literals, err := getWatchedStrings(txtFilePath) + if err != nil { + return fmt.Errorf("templ: failed to cache strings: %w", err) + } + + if index > len(literals) { + return fmt.Errorf("templ: failed to find line %d in %s", index, txtFilePath) + } + + s, err = strconv.Unquote(`"` + literals[index-1] + `"`) + if err != nil { + return err + } + } + _, err = io.WriteString(w, s) + return err +} + +var ( + watchModeCache = map[string]watchState{} + watchStateMutex sync.Mutex +) + +type watchState struct { + modTime time.Time + strings []string +} + +func getWatchedStrings(txtFilePath string) ([]string, error) { + watchStateMutex.Lock() + defer watchStateMutex.Unlock() + + state, cached := watchModeCache[txtFilePath] + if !cached { + return cacheStrings(txtFilePath) + } + + if time.Since(state.modTime) < time.Millisecond*100 { + return state.strings, nil + } + + info, err := os.Stat(txtFilePath) + if err != nil { + return nil, fmt.Errorf("templ: failed to stat %s: %w", txtFilePath, err) + } + + if !info.ModTime().After(state.modTime) { + return state.strings, nil + } + + return cacheStrings(txtFilePath) +} + +func cacheStrings(txtFilePath string) ([]string, error) { + txtFile, err := os.Open(txtFilePath) + if err != nil { + return nil, fmt.Errorf("templ: failed to open %s: %w", txtFilePath, err) + } + defer txtFile.Close() + + info, err := txtFile.Stat() + if err != nil { + return nil, fmt.Errorf("templ: failed to stat %s: %w", txtFilePath, err) + } + + all, err := io.ReadAll(txtFile) + if err != nil { + return nil, fmt.Errorf("templ: failed to read %s: %w", txtFilePath, err) + } + + literals := strings.Split(string(all), "\n") + watchModeCache[txtFilePath] = watchState{ + modTime: info.ModTime(), + strings: literals, + } + + return literals, nil +} diff --git a/templ/runtime_test.go b/templ/runtime_test.go new file mode 100644 index 0000000..95c7a26 --- /dev/null +++ b/templ/runtime_test.go @@ -0,0 +1,595 @@ +package templ_test + +import ( + "bytes" + "context" + "errors" + "fmt" + "html/template" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/a-h/templ" + "github.com/google/go-cmp/cmp" +) + +func TestCSSID(t *testing.T) { + t.Run("minimum hash suffix length is 8", func(t *testing.T) { + // See issue #978. + name := "classA" + css := "background-color:white;" + actual := len(templ.CSSID(name, css)) + expected := len(name) + 1 + 8 + if expected != actual { + t.Errorf("expected length %d, got %d", expected, actual) + } + }) + t.Run("known hash collisions are avoided", func(t *testing.T) { + name := "classA" + // Note that the first 4 characters of the hash are the same. + css1 := "grid-column:1;grid-row:1;" // After hash: f781266f + css2 := "grid-column:13;grid-row:6;" // After hash: f781f18b + id1 := templ.CSSID(name, css1) + id2 := templ.CSSID(name, css2) + if id1 == id2 { + t.Errorf("hash collision: %s == %s", id1, id2) + } + }) +} + +func TestCSSHandler(t *testing.T) { + tests := []struct { + name string + input []templ.CSSClass + expectedMIMEType string + expectedBody string + }{ + { + name: "no classes", + input: nil, + expectedMIMEType: "text/css", + expectedBody: "", + }, + { + name: "classes are rendered", + input: []templ.CSSClass{templ.ComponentCSSClass{ID: "className", Class: templ.SafeCSS(".className{background-color:white;}")}}, + expectedMIMEType: "text/css", + expectedBody: ".className{background-color:white;}", + }, + { + name: "classes are rendered", + input: []templ.CSSClass{ + templ.ComponentCSSClass{ID: "classA", Class: templ.SafeCSS(".classA{background-color:white;}")}, + templ.ComponentCSSClass{ID: "classB", Class: templ.SafeCSS(".classB{background-color:green;}")}, + }, + expectedMIMEType: "text/css", + expectedBody: ".classA{background-color:white;}.classB{background-color:green;}", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + h := templ.NewCSSHandler(tt.input...) + h.ServeHTTP(w, &http.Request{}) + if diff := cmp.Diff(tt.expectedMIMEType, w.Header().Get("Content-Type")); diff != "" { + t.Error(diff) + } + if diff := cmp.Diff(tt.expectedBody, w.Body.String()); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestCSSMiddleware(t *testing.T) { + pageHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if _, err := io.WriteString(w, "Hello, World!"); err != nil { + t.Fatalf("failed to write string: %v", err) + } + }) + c1 := templ.ComponentCSSClass{ + ID: "c1", + Class: ".c1{color:red}", + } + c2 := templ.ComponentCSSClass{ + ID: "c2", + Class: ".c2{color:blue}", + } + + tests := []struct { + name string + input *http.Request + handler http.Handler + expectedMIMEType string + expectedBody string + }{ + { + name: "accessing /style/templ.css renders CSS, even if it's empty", + input: httptest.NewRequest("GET", "/styles/templ.css", nil), + handler: templ.NewCSSMiddleware(pageHandler), + expectedMIMEType: "text/css", + expectedBody: "", + }, + { + name: "accessing /style/templ.css renders CSS that includes the classes", + input: httptest.NewRequest("GET", "/styles/templ.css", nil), + handler: templ.NewCSSMiddleware(pageHandler, c1, c2), + expectedMIMEType: "text/css", + expectedBody: ".c1{color:red}.c2{color:blue}", + }, + { + name: "the pageHandler is rendered", + input: httptest.NewRequest("GET", "/index.html", nil), + handler: templ.NewCSSMiddleware(pageHandler, c1, c2), + expectedMIMEType: "text/plain; charset=utf-8", + expectedBody: "Hello, World!", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + tt.handler.ServeHTTP(w, tt.input) + if diff := cmp.Diff(tt.expectedMIMEType, w.Header().Get("Content-Type")); diff != "" { + t.Error(diff) + } + if diff := cmp.Diff(tt.expectedBody, w.Body.String()); diff != "" { + t.Error(diff) + } + }) + } +} + +var cssInputs = []any{ + []string{"a", "b"}, // []string + "c", // string + templ.ConstantCSSClass("d"), // ConstantCSSClass + templ.ComponentCSSClass{ID: "e", Class: ".e{color:red}"}, // ComponentCSSClass + map[string]bool{"f": true, "ff": false}, // map[string]bool + templ.KV("g", true), // KeyValue[string, bool] + templ.KV("gg", false), // KeyValue[string, bool] + []templ.KeyValue[string, bool]{ + templ.KV("h", true), + templ.KV("hh", false), + }, // []KeyValue[string, bool] + templ.KV(templ.ConstantCSSClass("i"), true), // KeyValue[CSSClass, bool] + templ.KV(templ.ConstantCSSClass("ii"), false), // KeyValue[CSSClass, bool] + templ.KV(templ.ComponentCSSClass{ + ID: "j", + Class: ".j{color:red}", + }, true), // KeyValue[ComponentCSSClass, bool] + templ.KV(templ.ComponentCSSClass{ + ID: "jj", + Class: ".jj{color:red}", + }, false), // KeyValue[ComponentCSSClass, bool] + templ.CSSClasses{templ.ConstantCSSClass("k")}, // CSSClasses + func() templ.CSSClass { return templ.ConstantCSSClass("l") }, // func() CSSClass + templ.CSSClass(templ.ConstantCSSClass("m")), // CSSClass + customClass{name: "n"}, // CSSClass + []templ.CSSClass{customClass{name: "n"}}, // []CSSClass + templ.KV(templ.ConstantCSSClass("o"), true), // KeyValue[ConstantCSSClass, bool] + []templ.KeyValue[templ.ConstantCSSClass, bool]{ + templ.KV(templ.ConstantCSSClass("p"), true), + templ.KV(templ.ConstantCSSClass("pp"), false), + }, // []KeyValue[ConstantCSSClass, bool] +} + +type customClass struct { + name string +} + +func (cc customClass) ClassName() string { + return cc.name +} + +func TestRenderCSS(t *testing.T) { + c1 := templ.ComponentCSSClass{ + ID: "c1", + Class: ".c1{color:red}", + } + c2 := templ.ComponentCSSClass{ + ID: "c2", + Class: ".c2{color:blue}", + } + + tests := []struct { + name string + toIgnore []any + toRender []any + expected string + }{ + { + name: "if none are ignored, everything is rendered", + toIgnore: nil, + toRender: []any{c1, c2}, + expected: ``, + }, + { + name: "if something outside the expected is ignored, if has no effect", + toIgnore: []any{ + templ.ComponentCSSClass{ + ID: "c3", + Class: templ.SafeCSS(".c3{color:yellow}"), + }, + }, + toRender: []any{c1, c2}, + expected: ``, + }, + { + name: "if one is ignored, it's not rendered", + toIgnore: []any{c1}, + toRender: []any{c1, c2}, + expected: ``, + }, + { + name: "if all are ignored, not even style tags are rendered", + toIgnore: []any{ + c1, + c2, + templ.ComponentCSSClass{ + ID: "c3", + Class: templ.SafeCSS(".c3{color:yellow}"), + }, + }, + toRender: []any{c1, c2}, + expected: ``, + }, + { + name: "CSS classes are rendered", + toIgnore: nil, + toRender: cssInputs, + expected: ``, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + b := new(bytes.Buffer) + + // Render twice, reusing the same context so that there's a memory of which classes have been rendered. + ctx = templ.InitializeContext(ctx) + err := templ.RenderCSSItems(ctx, b, tt.toIgnore...) + if err != nil { + t.Fatalf("failed to render initial CSS: %v", err) + } + + // Now render again to check that only the expected classes were rendered. + b.Reset() + err = templ.RenderCSSItems(ctx, b, tt.toRender...) + if err != nil { + t.Fatalf("failed to render CSS: %v", err) + } + + if diff := cmp.Diff(tt.expected, b.String()); diff != "" { + t.Error(diff) + } + }) + } +} + +func TestClassesFunction(t *testing.T) { + tests := []struct { + name string + input []any + expected string + }{ + { + name: "constants are allowed", + input: []any{"a", "b", "c", ""}, + expected: "a b c ", + }, + { + name: "legacy CSS types are supported", + input: []any{"a", templ.SafeClass("b"), templ.Class("c")}, + expected: "a b c", + }, + { + name: "CSS components are included in the output", + input: []any{ + templ.ComponentCSSClass{ID: "classA", Class: templ.SafeCSS(".classA{background-color:white;}")}, + templ.ComponentCSSClass{ID: "classB", Class: templ.SafeCSS(".classB{background-color:green;}")}, + "c", + }, + expected: "classA classB c", + }, + { + name: "optional classes can be applied with expressions", + input: []any{ + "a", + templ.ComponentCSSClass{ID: "classA", Class: templ.SafeCSS(".classA{background-color:white;}")}, + templ.ComponentCSSClass{ID: "classB", Class: templ.SafeCSS(".classB{background-color:green;}")}, + "c", + map[string]bool{ + "a": false, + "classA": false, + "classB": false, + "c": true, + "d": false, + }, + }, + expected: "c", + }, + { + name: "unknown types for classes get rendered as --templ-css-class-unknown-type", + input: []any{ + 123, + map[string]string{"test": "no"}, + false, + "c", + }, + expected: "--templ-css-class-unknown-type c", + }, + { + name: "string arrays are supported", + input: []any{ + []string{"a", "b", "c", ""}, + "d", + }, + expected: "a b c d", + }, + { + name: "strings are broken up", + input: []any{ + "a ", + }, + expected: "a ", + }, + { + name: "if a templ.CSSClasses is passed in, the nested CSSClasses are extracted", + input: []any{ + templ.Classes( + "a", + templ.SafeClass("b"), + templ.Class("c"), + templ.ComponentCSSClass{ + ID: "d", + Class: "{}", + }, + ), + }, + expected: "a b c d", + }, + { + name: "kv types can be used to show or hide classes", + input: []any{ + "a", + templ.KV("b", true), + "c", + templ.KV("c", false), + templ.KV(templ.SafeClass("d"), true), + templ.KV(templ.SafeClass("e"), false), + }, + expected: "a b d", + }, + { + name: "an array of KV types can be used to show or hide classes", + input: []any{ + "a", + "c", + []templ.KeyValue[string, bool]{ + templ.KV("b", true), + templ.KV("c", false), + {"d", true}, + }, + }, + expected: "a b d", + }, + { + name: "the brackets on component CSS function calls can be elided", + input: []any{ + func() templ.CSSClass { + return templ.ComponentCSSClass{ + ID: "a", + Class: "", + } + }, + }, + expected: "a", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual := templ.Classes(test.input...).String() + if actual != test.expected { + t.Errorf("expected %q, got %q", test.expected, actual) + } + }) + } +} + +type baseError struct { + Value int +} + +func (baseError) Error() string { return "base error" } + +type nonMatchedError struct{} + +func (nonMatchedError) Error() string { return "non matched error" } + +func TestErrorWrapping(t *testing.T) { + baseErr := baseError{ + Value: 1, + } + wrappedErr := templ.Error{Err: baseErr, Line: 1, Col: 2} + t.Run("errors.Is() returns true for the base error", func(t *testing.T) { + if !errors.Is(wrappedErr, baseErr) { + t.Error("errors.Is() returned false for the base error") + } + }) + t.Run("errors.Is() returns false for a different error", func(t *testing.T) { + if errors.Is(wrappedErr, errors.New("different error")) { + t.Error("errors.Is() returned true for a different error") + } + }) + t.Run("errors.As() returns true for the base error", func(t *testing.T) { + var err baseError + if !errors.As(wrappedErr, &err) { + t.Error("errors.As() returned false for the base error") + } + if err.Value != 1 { + t.Errorf("errors.As() returned a different value: %v", err.Value) + } + }) + t.Run("errors.As() returns false for a different error", func(t *testing.T) { + var err nonMatchedError + if errors.As(wrappedErr, &err) { + t.Error("errors.As() returned true for a different error") + } + }) +} + +func TestRawComponent(t *testing.T) { + tests := []struct { + name string + input templ.Component + expected string + expectedErr error + }{ + { + name: "Raw content is not escaped", + input: templ.Raw("
    Test &
    "), + expected: `
    Test &
    `, + }, + { + name: "Raw will return errors first", + input: templ.Raw("", nil, errors.New("test error")), + expected: `
    Test &
    `, + expectedErr: errors.New("test error"), + }, + { + name: "Strings marked as safe are rendered without escaping", + input: templ.Raw(template.HTML("
    ")), + expected: `
    `, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + b := new(bytes.Buffer) + err := tt.input.Render(context.Background(), b) + if tt.expectedErr != nil { + expected := tt.expectedErr.Error() + actual := fmt.Sprintf("%v", err) + if actual != expected { + t.Errorf("expected error %q, got %q", expected, actual) + } + return + } + if err != nil { + t.Fatalf("failed to render content: %v", err) + } + if diff := cmp.Diff(tt.expected, b.String()); diff != "" { + t.Error(diff) + } + }) + } + t.Run("Raw does not require allocations", func(t *testing.T) { + actualAllocs := testing.AllocsPerRun(4, func() { + c := templ.Raw("
    ") + if c == nil { + t.Fatalf("unexpected nil value") + } + }) + if actualAllocs > 0 { + t.Errorf("expected no allocs, got %v", actualAllocs) + } + }) +} + +var goTemplate = template.Must(template.New("example").Parse("
    {{ . }}
    ")) + +func TestGoHTMLComponents(t *testing.T) { + t.Run("Go templates can be rendered as templ components", func(t *testing.T) { + b := new(bytes.Buffer) + err := templ.FromGoHTML(goTemplate, "Test &").Render(context.Background(), b) + if err != nil { + t.Fatalf("failed to render content: %v", err) + } + if diff := cmp.Diff("
    Test &
    ", b.String()); diff != "" { + t.Error(diff) + } + }) + t.Run("templ components can be rendered in Go templates", func(t *testing.T) { + b := new(bytes.Buffer) + c := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + _, err = io.WriteString(w, "
    Unsanitized &
    ") + return err + }) + h, err := templ.ToGoHTML(context.Background(), c) + if err != nil { + t.Fatalf("failed to convert to Go HTML: %v", err) + } + if err = goTemplate.Execute(b, h); err != nil { + t.Fatalf("failed to render content: %v", err) + } + if diff := cmp.Diff("
    Unsanitized &
    ", b.String()); diff != "" { + t.Error(diff) + } + }) + t.Run("errors in ToGoHTML are returned", func(t *testing.T) { + expectedErr := errors.New("test error") + c := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + return expectedErr + }) + _, err := templ.ToGoHTML(context.Background(), c) + if err == nil { + t.Fatalf("expected error, got nil") + } + if err != expectedErr { + t.Fatalf("expected error %q, got %q", expectedErr, err) + } + }) + t.Run("FromGoHTML does not require allocations", func(t *testing.T) { + actualAllocs := testing.AllocsPerRun(4, func() { + c := templ.FromGoHTML(goTemplate, "test &") + if c == nil { + t.Fatalf("unexpected nil value") + } + }) + if actualAllocs > 0 { + t.Errorf("expected no allocs, got %v", actualAllocs) + } + }) + t.Run("ToGoHTML requires one allocation", func(t *testing.T) { + expected := "
    Unsanitized &
    " + c := templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + _, err = io.WriteString(w, expected) + return err + }) + actualAllocs := testing.AllocsPerRun(4, func() { + h, err := templ.ToGoHTML(context.Background(), c) + if err != nil { + t.Fatalf("failed to convert to Go HTML: %v", err) + } + if h != template.HTML(expected) { + t.Fatalf("unexpected value") + } + }) + if actualAllocs > 1 { + t.Errorf("expected 1 alloc, got %v", actualAllocs) + } + }) +} + +func TestNonce(t *testing.T) { + ctx := context.Background() + t.Run("returns empty string if not set", func(t *testing.T) { + actual := templ.GetNonce(ctx) + if actual != "" { + t.Errorf("expected empty string got %q", actual) + } + }) + t.Run("returns value if one has been set", func(t *testing.T) { + expected := "abc123" + ctx := templ.WithNonce(context.Background(), expected) + actual := templ.GetNonce(ctx) + if actual != expected { + t.Errorf("expected %q got %q", expected, actual) + } + }) +} diff --git a/templ/safehtml/style.go b/templ/safehtml/style.go new file mode 100644 index 0000000..174c3c4 --- /dev/null +++ b/templ/safehtml/style.go @@ -0,0 +1,199 @@ +// Adapted from https://raw.githubusercontent.com/google/safehtml/3c4cd5b5d8c9a6c5882fba099979e9f50b65c876/style.go + +// Copyright (c) 2017 The Go Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +package safehtml + +import ( + "bytes" + "fmt" + "net/url" + "regexp" + "strings" +) + +// SanitizeCSS attempts to sanitize CSS properties. +func SanitizeCSS(property, value string) (string, string) { + property = SanitizeCSSProperty(property) + if property == InnocuousPropertyName { + return InnocuousPropertyName, InnocuousPropertyValue + } + return property, SanitizeCSSValue(property, value) +} + +func SanitizeCSSValue(property, value string) string { + if sanitizer, ok := cssPropertyNameToValueSanitizer[property]; ok { + return sanitizer(value) + } + return sanitizeRegular(value) +} + +func SanitizeCSSProperty(property string) string { + if !identifierPattern.MatchString(property) { + return InnocuousPropertyName + } + return strings.ToLower(property) +} + +// identifierPattern matches a subset of valid values defined in +// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram. This pattern matches all generic family name +// keywords defined in https://drafts.csswg.org/css-fonts-3/#family-name-value. +var identifierPattern = regexp.MustCompile(`^[-a-zA-Z]+$`) + +var cssPropertyNameToValueSanitizer = map[string]func(string) string{ + "background-image": sanitizeBackgroundImage, + "font-family": sanitizeFontFamily, + "display": sanitizeEnum, + "background-color": sanitizeRegular, + "background-position": sanitizeRegular, + "background-repeat": sanitizeRegular, + "background-size": sanitizeRegular, + "color": sanitizeRegular, + "height": sanitizeRegular, + "width": sanitizeRegular, + "left": sanitizeRegular, + "right": sanitizeRegular, + "top": sanitizeRegular, + "bottom": sanitizeRegular, + "font-weight": sanitizeRegular, + "padding": sanitizeRegular, + "z-index": sanitizeRegular, +} + +var validURLPrefixes = []string{ + `url("`, + `url('`, + `url(`, +} + +var validURLSuffixes = []string{ + `")`, + `')`, + `)`, +} + +func sanitizeBackgroundImage(v string) string { + // Check for <> as per https://github.com/google/safehtml/blob/be23134998433fcf0135dda53593fc8f8bf4df7c/style.go#L87C2-L89C3 + if strings.ContainsAny(v, "<>") { + return InnocuousPropertyValue + } + for _, u := range strings.Split(v, ",") { + u = strings.TrimSpace(u) + var found bool + for i, prefix := range validURLPrefixes { + if strings.HasPrefix(u, prefix) && strings.HasSuffix(u, validURLSuffixes[i]) { + found = true + u = strings.TrimPrefix(u, validURLPrefixes[i]) + u = strings.TrimSuffix(u, validURLSuffixes[i]) + break + } + } + if !found || !urlIsSafe(u) { + return InnocuousPropertyValue + } + } + return v +} + +func urlIsSafe(s string) bool { + u, err := url.Parse(s) + if err != nil { + return false + } + if u.IsAbs() { + if strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https") || strings.EqualFold(u.Scheme, "mailto") { + return true + } + return false + } + return true +} + +var genericFontFamilyName = regexp.MustCompile(`^[a-zA-Z][- a-zA-Z]+$`) + +func sanitizeFontFamily(s string) string { + for _, f := range strings.Split(s, ",") { + f = strings.TrimSpace(f) + if strings.HasPrefix(f, `"`) { + if !strings.HasSuffix(f, `"`) { + return InnocuousPropertyValue + } + continue + } + if !genericFontFamilyName.MatchString(f) { + return InnocuousPropertyValue + } + } + return s +} + +func sanitizeEnum(s string) string { + if !safeEnumPropertyValuePattern.MatchString(s) { + return InnocuousPropertyValue + } + return s +} + +func sanitizeRegular(s string) string { + if !safeRegularPropertyValuePattern.MatchString(s) { + return InnocuousPropertyValue + } + return s +} + +// InnocuousPropertyName is an innocuous property generated by a sanitizer when its input is unsafe. +const InnocuousPropertyName = "zTemplUnsafeCSSPropertyName" + +// InnocuousPropertyValue is an innocuous property generated by a sanitizer when its input is unsafe. +const InnocuousPropertyValue = "zTemplUnsafeCSSPropertyValue" + +// safeRegularPropertyValuePattern matches strings that are safe to use as property values. +// Specifically, it matches string where every '*' or '/' is followed by end-of-text or a safe rune +// (i.e. alphanumerics or runes in the set [+-.!#%_ \t]). This regex ensures that the following +// are disallowed: +// - "/*" and "*/", which are CSS comment markers. +// - "//", even though this is not a comment marker in the CSS specification. Disallowing +// this string minimizes the chance that browser peculiarities or parsing bugs will allow +// sanitization to be bypassed. +// - '(' and ')', which can be used to call functions. +// - ',', since it can be used to inject extra values into a property. +// - Runes which could be matched on CSS error recovery of a previously malformed token, such as '@' +// and ':'. See http://www.w3.org/TR/css3-syntax/#error-handling. +var safeRegularPropertyValuePattern = regexp.MustCompile(`^(?:[*/]?(?:[0-9a-zA-Z+-.!#%_ \t]|$))*$`) + +// safeEnumPropertyValuePattern matches strings that are safe to use as enumerated property values. +// Specifically, it matches strings that contain only alphabetic and '-' runes. +var safeEnumPropertyValuePattern = regexp.MustCompile(`^[a-zA-Z-]*$`) + +// SanitizeStyleValue escapes s so that it is safe to put between "" to form a CSS . +// See syntax at https://www.w3.org/TR/css-syntax-3/#string-token-diagram. +// +// On top of the escape sequences required in , this function also escapes +// control runes to minimize the risk of these runes triggering browser-specific bugs. +// Taken from cssEscapeString in safehtml package. +func SanitizeStyleValue(s string) string { + var b bytes.Buffer + b.Grow(len(s)) + for _, c := range s { + switch { + case c == '\u0000': + // Replace the NULL byte according to https://www.w3.org/TR/css-syntax-3/#input-preprocessing. + // We take this extra precaution in case the user agent fails to handle NULL properly. + b.WriteString("\uFFFD") + case c == '<', // Prevents breaking out of a style element with ``. Escape this in case the Style user forgets to. + c == '"', c == '\\', // Must be CSS-escaped in . U+000A line feed is handled in the next case. + c <= '\u001F', c == '\u007F', // C0 control codes + c >= '\u0080' && c <= '\u009F', // C1 control codes + c == '\u2028', c == '\u2029': // Unicode newline characters + // See CSS escape sequence syntax at https://www.w3.org/TR/css-syntax-3/#escape-diagram. + fmt.Fprintf(&b, "\\%06X", c) + default: + b.WriteRune(c) + } + } + return b.String() +} diff --git a/templ/safehtml/style_test.go b/templ/safehtml/style_test.go new file mode 100644 index 0000000..c55a44a --- /dev/null +++ b/templ/safehtml/style_test.go @@ -0,0 +1,362 @@ +package safehtml + +import "testing" + +func TestSanitizeCSS(t *testing.T) { + tests := []struct { + name string + inputProperty string + expectedProperty string + inputValue string + expectedValue string + }{ + { + name: "directions are allowed", + inputProperty: "dir", + expectedProperty: "dir", + inputValue: "ltr", + expectedValue: "ltr", + }, + { + name: "border-left allowed", + inputProperty: "border-left", + expectedProperty: "border-left", + inputValue: "0", + expectedValue: "0", + }, + { + name: "border can contain multiple values", + inputProperty: "border", + expectedProperty: "border", + inputValue: `1 1 1 1`, + expectedValue: `1 1 1 1`, + }, + { + name: "properties are case corrected", + inputProperty: "Border", + expectedProperty: "border", + inputValue: `1 1 1 1`, + expectedValue: `1 1 1 1`, + }, + { + name: "expressions are not allowed", + inputProperty: "width", + expectedProperty: "width", + inputValue: `expression(alert(1337))`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "font-family standard values are allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `sans-serif`, + expectedValue: `sans-serif`, + }, + { + name: "font-family values with spaces are allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `Akzidenz Grotesk`, + expectedValue: `Akzidenz Grotesk`, + }, + { + name: "font-family multiple standard values are allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `sans-serif, monospaced`, + expectedValue: `sans-serif, monospaced`, + }, + { + name: "font-family multiple quoted and non-quoted values are allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `"Georgia", monospaced, sans-serif`, + expectedValue: `"Georgia", monospaced, sans-serif`, + }, + { + name: "font-family Chinese names are allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `"中易宋体", monospaced`, + expectedValue: `"中易宋体", monospaced`, + }, + { + name: "font-family quoted values must be terminated", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `"quotes`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "font-family non standard names are not allowed", + inputProperty: "font-family", + expectedProperty: "font-family", + inputValue: `foo@bar`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "obfuscated values are not allowed", + inputProperty: "width", + expectedProperty: "width", + inputValue: ` e\\78preS\x00Sio/**/n(alert(1337))`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "moz binding blocked", + inputProperty: "-moz-binding(alert(1337))", + expectedProperty: InnocuousPropertyName, + inputValue: `something`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "obfuscated moz-binding blocked", + inputProperty: " -mo\\7a-B\x00I/**/nding(alert(1337))", + expectedProperty: InnocuousPropertyName, + inputValue: `something`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "angle brackets in property value", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url(/img?name=O'Reilly Animal(1)<2>.png)`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "angle brackets in quoted property value", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("/img?name=O'Reilly Animal(1)<2>.png")`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background", + inputProperty: "background", + expectedProperty: "background", + inputValue: "url(/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png)", + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image JS URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url(javascript:alert(1337))`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image VBScript URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url(vbscript:alert(1337))`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image absolute FTP URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("ftp://safe.example.com/img.png")`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image invalid URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("` + string([]byte{0x7f}) + `")`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image invalid prefix", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `/img.png")`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image invalid suffix", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("/img.png`, + expectedValue: InnocuousPropertyValue, + }, + { + name: "background-image safe URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("/img.png")`, + expectedValue: `url("/img.png")`, + }, + { + name: "background-image safe URL - two slashes", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("//img.png")`, + expectedValue: `url("//img.png")`, + }, + { + name: "background-image safe HTTP URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("http://safe.example.com/img.png")`, + expectedValue: `url("http://safe.example.com/img.png")`, + }, + { + name: "background-image safe mailto URL", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("mailto:foo@bar.foo")`, + expectedValue: `url("mailto:foo@bar.foo")`, + }, + { + name: "background-image multiple URLs", + inputProperty: "background-image", + expectedProperty: "background-image", + inputValue: `url("http://safe.example.com/img.png"), url("https://safe.example.com/other.png")`, + expectedValue: `url("http://safe.example.com/img.png"), url("https://safe.example.com/other.png")`, + }, + { + name: "-webkit-text-stroke-color safe webkit", + inputProperty: "-webkit-text-stroke-color", + expectedProperty: "-webkit-text-stroke-color", + inputValue: `#000`, + expectedValue: `#000`, + }, + { + name: "escape attempt property name", + inputProperty: "