diff --git a/0.25.3/404.html b/0.25.3/404.html index 6d415de40..6d570d706 100644 --- a/0.25.3/404.html +++ b/0.25.3/404.html @@ -1 +1 @@ - Leapp - Docs
\ No newline at end of file + Leapp - Docs

The page you are looking for does not exist

404 image
\ No newline at end of file diff --git a/0.25.3/assets/javascripts/bundle.ede584c9.min.js b/0.25.3/assets/javascripts/bundle.13690f9d.min.js similarity index 59% rename from 0.25.3/assets/javascripts/bundle.ede584c9.min.js rename to 0.25.3/assets/javascripts/bundle.13690f9d.min.js index 172ddfce1..3221c5efd 100644 --- a/0.25.3/assets/javascripts/bundle.ede584c9.min.js +++ b/0.25.3/assets/javascripts/bundle.13690f9d.min.js @@ -1,3 +1,3 @@ -"use strict";(()=>{var Bi=Object.create;var _r=Object.defineProperty;var Gi=Object.getOwnPropertyDescriptor;var Ji=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Xi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,j=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ji(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Gi(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Bi(Xi(e)):{},Zi(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var mt=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[mt]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function g(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",g,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Yi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(z){try{return document.execCommand(z)}catch(C){return!1}}var d=function(C){var M=f()(C);return u("cut"),M},g=d;function L(z){var C=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(D,"px"),M.setAttribute("readonly",""),M.value=z,M}var ee=function(C,M){var D=L(C);M.container.appendChild(D);var N=f()(D);return u("copy"),D.remove(),N},ne=function(C){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,M):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,M):(D=f()(C),u("copy")),D},Z=ne;function H(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(M){return typeof M}:H=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},H(z)}var mt=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=C.action,D=M===void 0?"copy":M,N=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:N});if(G)return D==="cut"?g(G):Z(G,{container:N})},Fe=mt;function R(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(M){return typeof M}:R=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},R(z)}function se(z,C){if(!(z instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(z,C){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=R(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var G=this;this.listener=p()(N,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(N){var G=N.delegateTarget||N.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return Mr("action",N)}},{key:"defaultTarget",value:function(N){var G=Mr("target",N);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(N){return Mr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(N,G)}},{key:"cut",value:function(N){return g(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof N=="string"?[N]:N,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),M}(a()),Yi=Qi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,g){var L=p.apply(this,arguments);return l.addEventListener(u,L,g),{destroy:function(){l.removeEventListener(u,L,g)}}}function c(l,f,u,d,g){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,g)}))}function p(l,f,u,d){return function(g){g.delegateTarget=s(g.target,f),g.delegateTarget&&d.call(l,g)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,g){if(!u&&!d&&!g)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(g))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,g);if(s.nodeList(u))return l(u,d,g);if(s.string(u))return f(u,d,g);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,g){return u.addEventListener(d,g),{destroy:function(){u.removeEventListener(d,g)}}}function l(u,d,g){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,g)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,g)})}}}function f(u,d,g){return a(document.body,u,d,g)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var fs=/["'&<>]/;di.exports=us;function us(e){var t=""+e,r=fs.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function q(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function Y(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(g){f(i[0][3],g)}}function c(u){u.value instanceof ft?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Se=="function"?Se(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function P(e){return typeof e=="function"}function gt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=gt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +"use strict";(()=>{var Bi=Object.create;var _r=Object.defineProperty;var Gi=Object.getOwnPropertyDescriptor;var Ji=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Xi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,j=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ji(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Gi(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Bi(Xi(e)):{},Zi(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var ft=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[ft]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function g(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",g,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Yi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(z){try{return document.execCommand(z)}catch(C){return!1}}var d=function(C){var _=f()(C);return u("cut"),_},g=d;function L(z){var C=document.documentElement.getAttribute("dir")==="rtl",_=document.createElement("textarea");_.style.fontSize="12pt",_.style.border="0",_.style.padding="0",_.style.margin="0",_.style.position="absolute",_.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return _.style.top="".concat(D,"px"),_.setAttribute("readonly",""),_.value=z,_}var ee=function(C,_){var D=L(C);_.container.appendChild(D);var N=f()(D);return u("copy"),D.remove(),N},ne=function(C){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,_):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,_):(D=f()(C),u("copy")),D},Z=ne;function H(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(_){return typeof _}:H=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},H(z)}var ft=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},_=C.action,D=_===void 0?"copy":_,N=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:N});if(G)return D==="cut"?g(G):Z(G,{container:N})},Fe=ft;function R(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(_){return typeof _}:R=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},R(z)}function se(z,C){if(!(z instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(z,C){for(var _=0;_0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=R(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var G=this;this.listener=p()(N,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(N){var G=N.delegateTarget||N.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return Mr("action",N)}},{key:"defaultTarget",value:function(N){var G=Mr("target",N);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(N){return Mr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(N,G)}},{key:"cut",value:function(N){return g(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof N=="string"?[N]:N,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),_}(a()),Yi=Qi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,g){var L=p.apply(this,arguments);return l.addEventListener(u,L,g),{destroy:function(){l.removeEventListener(u,L,g)}}}function c(l,f,u,d,g){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,g)}))}function p(l,f,u,d){return function(g){g.delegateTarget=s(g.target,f),g.delegateTarget&&d.call(l,g)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,g){if(!u&&!d&&!g)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(g))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,g);if(s.nodeList(u))return l(u,d,g);if(s.string(u))return f(u,d,g);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,g){return u.addEventListener(d,g),{destroy:function(){u.removeEventListener(d,g)}}}function l(u,d,g){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,g)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,g)})}}}function f(u,d,g){return a(document.body,u,d,g)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var fs=/["'&<>]/;di.exports=us;function us(e){var t=""+e,r=fs.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function q(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function B(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(g){f(i[0][3],g)}}function c(u){u.value instanceof ut?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Oe=="function"?Oe(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function P(e){return typeof e=="function"}function xt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=xt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: `+r.map(function(o,n){return n+1+") "+o.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Je(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var ze=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Se(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(P(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Se(f),d=u.next();!d.done;d=u.next()){var g=d.value;try{wo(g)}catch(L){i=i!=null?i:[],L instanceof Xt?i=Y(Y([],q(i)),q(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Je(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Je(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var $r=ze.EMPTY;function Zt(e){return e instanceof ze||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function wo(e){P(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var xt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?$r:(this.currentObservers=null,a.push(r),new ze(function(){o.currentObservers=null,Je(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(I);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:$r},t}(w);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(w);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(Tt);var $o=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(St);var Dr=new $o(ko);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=wt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(wt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(Tt);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(St);var ge=new Po(Ro);var x=new I(function(e){return e.complete()});function rr(e){return e&&P(e.schedule)}function Nr(e){return e[e.length-1]}function st(e){return P(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Ot=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return P(e==null?void 0:e.then)}function ir(e){return P(e[Et])}function ar(e){return Symbol.asyncIterator&&P(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ca(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=ca();function pr(e){return P(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ft(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ft(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ft(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return P(e==null?void 0:e.getReader)}function U(e){if(e instanceof I)return e;if(e!=null){if(ir(e))return pa(e);if(Ot(e))return la(e);if(nr(e))return ma(e);if(ar(e))return Io(e);if(pr(e))return fa(e);if(mr(e))return ua(e)}throw sr(e)}function pa(e){return new I(function(t){var r=e[Et]();if(P(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function la(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,ye(1),r?tt(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return x}:y(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new w}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,g=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,g=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return y(function(H,mt){d++,!L&&!g&&ee();var Fe=u=u!=null?u:r();mt.add(function(){d--,d===0&&!L&&!g&&(f=Br(Z,c))}),Fe.subscribe(mt),!l&&d>0&&(l=new dt({next:function(R){return Fe.next(R)},error:function(R){L=!0,ee(),f=Br(ne,n,R),Fe.error(R)},complete:function(){g=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function A(e,t=document){return Array.from(t.querySelectorAll(e))}function F(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var Ha=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),K(void 0),m(()=>Ve()||document.body),X(1));function Ke(e){return Ha.pipe(m(t=>e.contains(t)),Q())}function ot(e,t){return k(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>ke(+!r*t)):be,K(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function _t(e){let t=S("script",{src:e});return k(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),ye(1))))}var an=new w,ka=k(()=>typeof ResizeObserver=="undefined"?_t("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(Ze,$(e)).pipe(_(()=>e.disconnect()))),X(1));function ue(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(T(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ue(e)),K(ue(e)))}function At(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Qe(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe($e(0,ge),m(()=>Qe(e)),K(Qe(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ye(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe($e(0,ge),m(()=>gr(e)),K(gr(e)))}var ln=new w,$a=k(()=>$(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(Ze,$(e)).pipe(_(()=>e.disconnect()))),X(1));function Ct(e){return $a.pipe(T(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ye(e).pipe(m(({y:r})=>{let o=ue(e),n=At(e);return r>=n.height-o.height-t}),Q())}var xr={drawer:F("[data-md-toggle=drawer]"),search:F("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function nt(e,t){xr[e].checked!==t&&xr[e].click()}function Be(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),K(t.checked))}function Ra(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(K(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Ra(o,r)}return!0}),le());return Pa().pipe(b(t=>t?x:e))}function Ee(){return new URL(location.href)}function it(e,t=!1){if(B("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new w}function hn(){return location.hash.slice(1)}function bn(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),K(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>fe(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(K(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(K(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():x))}function to(e,t){return new I(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ge(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),K(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),K(wn()))}function Sn(){return V([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=V([o,r]).pipe(m(()=>Qe(e)));return V([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Ia(e){return h(e,"message",t=>t.data)}function Fa(e){let t=new w;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Ia(t),o=Fa(t),n=new w;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var ja=F("#__config"),Ht=JSON.parse(ja.textContent);Ht.base=`${new URL(Ht.base,Ee())}`;function we(){return Ht}function B(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return F(`[data-md-component=${e}]`,t)}function me(e,t=document){return A(`[data-md-component=${e}]`,t)}function Ua(e){let t=F(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>F(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!B("announce.dismiss")||!e.childElementCount)return x;if(!e.hidden){let t=F(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return k(()=>{let t=new w;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Ua(e).pipe(T(r=>t.next(r)),_(()=>t.complete()),m(r=>j({ref:e},r)))})}function Wa(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new w;return r.subscribe(({hidden:o})=>{e.hidden=o}),Wa(e,t).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))}function Dt(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return S("div",{class:"md-tooltip2",role:"dialog"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return S("div",{class:"md-tooltip2",role:"tooltip"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function Cn(e){return S("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return S("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function kn(){return S("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=we(),s=new URL(e.location,i.base);B("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=we();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function $n(e){let t=e[0].score,r=[...e],o=we(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function Rn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function Da(e){let t=we(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function In(e,t){return e=e.filter(r=>{var o;return!((o=r.properties)!=null&&o.hidden)}),S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":Me("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(Da)))}var Na=0;function Va(e,t=250){let r=V([Ke(e),ot(e,t)]).pipe(m(([n,i])=>n||i),Q()),o=k(()=>sn(e)).pipe(J(Ye),vt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>V([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Na++}`;return k(()=>{let s=new w,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>ke(+!l*250,Dr)),Q(),b(l=>l?o:x),T(l=>l.id=i),le());V([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>ot(l,250)),K(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),g=d.width/2;if(f.role==="tooltip")return{x:g,y:8+d.height};if(d.y>=u.height/2){let{height:L}=ue(f);return{x:g,y:-16-L}}else return{x:g,y:16+d.height}}));return V([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=ue(F(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Q(),xe(ge),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),V([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Va(e,r).pipe(T(l=>s.next(l)),_(()=>s.complete()),m(l=>j({ref:e},l)))})}function pt(e,{viewport$:t},r=document.body){return Nt(e,{content$:new I(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function za(e,t){let r=k(()=>V([pn(e),Ye(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=ue(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ke(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),ye(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return k(()=>{let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),Ct(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe($e(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(vt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),rt(125)).subscribe(()=>e.focus()),za(e,t).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))})}function qa(e){let t=we();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return A(r.join(", "),e)}function Ka(e){let t=[];for(let r of qa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ka(t)){let[,c]=a.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?x:k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([F(".md-typeset",f),F(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(_(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return k(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):x})}var Nn=Gt(io());var Qa=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(K(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ya(e){return Le(e).pipe(m(({width:t})=>({scrollable:At(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=k(()=>{let n=new w,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Qa++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||B("content.code.annotate"))){let g=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Q(),b(L=>L?g:x)))}}let u=A(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||B("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),g=Hn();s.push(g),B("content.tooltips")&&l.push(pt(g,{viewport$}));let L=h(g,"click").pipe(Ut(R=>!R,!1),T(()=>g.blur()),le());L.subscribe(R=>{g.classList.toggle("md-code__button--active",R)});let ee=de(u).pipe(J(R=>ot(R).pipe(m(se=>[R,se]))));L.pipe(b(R=>R?ee:x)).subscribe(([R,se])=>{let ce=fe(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let ne=de(u).pipe(J(R=>h(R,"mousedown").pipe(T(se=>se.preventDefault()),m(()=>R)))),Z=L.pipe(b(R=>R?ne:x),te(Dn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Te=A(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Te),Math.max(ce,...Te)]}})),H=Zr(x).pipe(v(R=>R.startsWith(`__codelineno-${p}-`)));H.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Te=>+Te-d+1);ce.length===1&&ce.push(ce[0]);for(let Te of A(".hll:not(.select)",e))Te.replaceWith(...Array.from(Te.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Te of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Te.childNodes).slice(1)),Te.append(je)}}),H.pipe(ye(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=de(A('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(T(se=>se.preventDefault()),m(()=>R)))).pipe(W(i),te(Dn),m(([R,se])=>{let he=+F(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Te=A(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Te),Math.max(he,...Te)]}}));O(Z,Fe).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),B("content.tooltips")&&l.push(pt(d,{viewport$}))}if(s.length){let d=kn();d.append(...s),a.insertBefore(d,e)}return Ya(e).pipe(T(d=>n.next(d)),_(()=>n.complete()),m(d=>j({ref:e},d)),Ne(O(...l).pipe(W(i))))});return B("content.lazy")?Ct(e).pipe(v(n=>n),ye(1),b(()=>o)):o}function Ba(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return k(()=>{let r=new w;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ba(e,t).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function Ga(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Ja(e,t){for(let r of A("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}return $(e)}function Kn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return x;if(!(B("navigation.instant.preview")||e.hasAttribute("data-preview")))return x;let o=V([Ke(e),ot(e)]).pipe(m(([i,s])=>i||s),Q(),v(i=>i));return ht([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?$(s):x}),b(i=>yr(i).pipe(b(s=>Ja(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=fe(s,i);return typeof a=="undefined"?x:$(Ga(a))})).pipe(b(i=>{let s=new I(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,j({content$:s},t))}))}var Qn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,Za=0;function es(){return typeof mermaid=="undefined"||mermaid instanceof Element?_t("https://unpkg.com/mermaid@10.7.0/dist/mermaid.min.js"):$(void 0)}function Yn(e){return e.classList.remove("mermaid"),ao||(ao=es().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Qn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Za++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Bn=S("table");function Gn(e){return e.replaceWith(Bn),Bn.replaceWith(Pn(e)),$({ref:e})}function ts(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>F(`label[for="${r.id}"]`))))).pipe(K(F(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Jn(e,{viewport$:t,target$:r}){let o=F(".tabbed-labels",e),n=A(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),k(()=>{let a=new w,c=a.pipe(re(),ae(!0));V([a,Le(e)]).pipe(W(c),$e(1,ge)).subscribe({next([{active:p},l]){let f=Qe(p),{width:u}=ue(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),V([Ye(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=At(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=ue(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=F(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let g of A("[data-tabs]"))for(let L of A(":scope > input",g)){let ee=F(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of A("audio, video",e))p.pause()}),ts(n).pipe(T(p=>a.next(p)),_(()=>a.complete()),m(p=>j({ref:e},p)))}).pipe(Xe(pe))}function Xn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...A(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...A("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...A("a:not([title])",e).map(i=>Kn(i,t)),...A("pre.mermaid",e).map(i=>Yn(i)),...A("table:not([class])",e).map(i=>Gn(i)),...A("details",e).map(i=>qn(i,{target$:o,print$:n})),...A("[data-tabs]",e).map(i=>Jn(i,{viewport$:r,target$:o})),...A("[title]",e).filter(()=>B("content.tooltips")).map(i=>pt(i,{viewport$:r})),...A(".footnote-ref",e).filter(()=>B("content.footnote.tooltips")).map(i=>Nt(i,{content$:new I(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function rs(e,{alert$:t}){return t.pipe(b(r=>O($(!0),$(!1).pipe(rt(2e3))).pipe(m(o=>({message:r,active:o})))))}function Zn(e,t){let r=F(".md-typeset",e);return k(()=>{let o=new w;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),rs(e,t).pipe(T(n=>o.next(n)),_(()=>o.complete()),m(n=>j({ref:e},n)))})}var os=0;function ns(e,t){document.body.append(e);let{width:r}=ue(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ye(o):$({x:0,y:0}),i=O(Ke(t),ot(t)).pipe(Q());return V([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Qe(t),l=ue(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ei(e){let t=e.title;if(!t.length)return x;let r=`__tooltip_${os++}`,o=Dt(r,"inline"),n=F(".md-typeset",o);return n.innerHTML=t,k(()=>{let i=new w;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe($e(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(vt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),ns(o,e).pipe(T(s=>i.next(s)),_(()=>i.complete()),m(s=>j({ref:e},s)))}).pipe(Xe(pe))}function is({viewport$:e}){if(!B("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),et(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Q()),o=Be("search");return V([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Q(),b(n=>n?r:$(!1)),K(!1))}function ti(e,t){return k(()=>V([Le(e),is(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Q((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function ri(e,{header$:t,main$:r}){return k(()=>{let o=new w,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=de(A("[title]",e)).pipe(v(()=>B("content.tooltips")),J(s=>ei(s)));return r.subscribe(o),t.pipe(W(n),m(s=>j({ref:e},s)),Ne(i.pipe(W(n))))})}function as(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ue(e);return{active:o>=n}}),oe("active"))}function oi(e,t){return k(()=>{let r=new w;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?x:as(o,t).pipe(T(n=>r.next(n)),_(()=>r.complete()),m(n=>j({ref:e},n)))})}function ni(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Q()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return V([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Q((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function ss(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),K(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ii(e){let t=A("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return k(()=>{let i=new w;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),ss(t).pipe(W(n.pipe(Pe(1))),bt(),T(s=>i.next(s)),_(()=>i.complete()),m(s=>j({ref:e},s)))})}function ai(e,{progress$:t}){return k(()=>{let r=new w;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}function si(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function cs(e,t){let r=new Map;for(let o of A("url",e)){let n=F("loc",o),i=[si(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of A("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(si(new URL(a),t))}}return r}function kt(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>cs(t,new URL(e))),Oe(()=>$(new Map)),le())}function ci({document$:e}){let t=new Map;e.pipe(b(()=>A("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>kt(r).pipe(m(o=>[r,o])))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(f));if(typeof n=="undefined")return x;let[i,s]=n,a=Ee();if(a.href.startsWith(i))return x;let c=we(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),$(l)}}return x})).subscribe(r=>it(r,!0))}var so=Gt(io());function ps(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function pi({alert$:e}){so.default.isSupported()&&new I(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ps(F(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function li(e,t){if(!(e.target instanceof Element))return x;let r=e.target.closest("a");if(r===null)return x;if(r.target||e.metaKey||e.ctrlKey)return x;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(r)):x}function mi(e){let t=new Map;for(let r of A(":scope > *",e.head))t.set(r.outerHTML,r);return t}function fi(e){for(let t of A("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function ls(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=mi(document);for(let[o,n]of mi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return qe(A("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new I(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),x}),re(),ae(document))}function ui({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return x;$(document).subscribe(fi);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>li(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(Ee),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(Oe(()=>(it(a,!0),x)))),b(fi),b(ls),le());return O(s.pipe(te(t,(a,c)=>c)),t.pipe(oe("pathname"),b(()=>t),oe("hash")),t.pipe(Q((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),T(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),B("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>li(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),ye(1))})).subscribe(a=>a.remove()),s}var bi=Gt(hi());function vi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,bi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function gi(e,t){let r=On(e);return O($(location.protocol!=="file:"),Be("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function xi({document$:e}){let t=we(),r=Ge(new URL("../versions.json",t.base)).pipe(Oe(()=>x)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?x:(i.preventDefault(),$(c))}}return x}),b(i=>{let{version:s}=n.get(i);return kt(new URL(i)).pipe(m(a=>{let p=Ee().href.replace(t.base,"");return a.has(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>it(n,!0)),V([r,o]).subscribe(([n,i])=>{F(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function hs(e,{worker$:t}){let{searchParams:r}=Ee();r.has("q")&&(nt("search",!0),e.value=r.get("q"),e.focus(),Be("search").pipe(Re(i=>!i)).subscribe(()=>{let i=Ee();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ke(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Q());return V([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function yi(e,{worker$:t}){let r=new w,o=r.pipe(re(),ae(!0));V([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&nt("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=F("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),hs(e,{worker$:t}).pipe(T(i=>r.next(i)),_(()=>r.complete()),m(i=>j({ref:e},i)),X(1))}function Ei(e,{worker$:t,query$:r}){let o=new w,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=F(":scope > :first-child",e),a=F(":scope > :last-child",e);Be("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),b(({items:l})=>O($(...l.slice(0,10)),$(...l.slice(10)).pipe(et(4),Xr(n),b(([f])=>f)))),m($n),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=fe("details",l);return typeof f=="undefined"?x:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),_(()=>o.complete()),m(l=>j({ref:e},l)))}function bs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=Ee();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function wi(e,t){let r=new w,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),bs(e,t).pipe(T(n=>r.next(n)),_(()=>r.complete()),m(n=>j({ref:e},n)))}function Ti(e,{worker$:t,keyboard$:r}){let o=new w,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Q());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),_(()=>o.complete()),m(()=>({ref:e})))}function Si(e,{index$:t,keyboard$:r}){let o=we();try{let n=gi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>nt("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of A(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":nt("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...A(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=yi(i,{worker$:n});return O(a,Ei(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>wi(c,{query$:a})),...me("search-suggest",e).map(c=>Ti(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ze}}function Oi(e,{index$:t,location$:r}){return V([t,r.pipe(K(Ee()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>vi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function vs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return V([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Q((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=F(".md-sidebar__scrollwrap",e),{y:s}=Qe(i);return k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=a.pipe($e(0,ge));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of A(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ue(f);f.scrollTo({top:u-d/2})}}}),de(A("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),W(c)))).subscribe(l=>{let f=F(`[id="${l.htmlFor}"]`);F(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),vs(e,r).pipe(T(l=>a.next(l)),_(()=>a.complete()),m(l=>j({ref:e},l)))})}function Li(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return ht(Ge(`${r}/releases/latest`).pipe(Oe(()=>x),m(o=>({version:o.tag_name})),tt({})),Ge(r).pipe(Oe(()=>x),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),tt({}))).pipe(m(([o,n])=>j(j({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(m(o=>({repositories:o.public_repos})),tt({}))}}function Mi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(Oe(()=>x),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),tt({}))}function _i(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Li(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Mi(r,o)}return x}var gs;function xs(e){return gs||(gs=k(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return x}return _i(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(Oe(()=>x),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ai(e){let t=F(":scope > :last-child",e);return k(()=>{let r=new w;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),xs(e).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function ys(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Ci(e,t){return k(()=>{let r=new w;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?$({hidden:!1}):ys(e,t)).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){let o=new Map,n=A(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=fe(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=F(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>k(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let g=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!g)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Q((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),K({prev:[],next:[]}),et(2,1),m(([a,c])=>a.prev.length{let i=new w,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),B("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ue(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return B("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),bt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=Ee(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Es(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))})}function ws(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),et(2,1),m(([s,a])=>s>a&&a>0),Q()),i=r.pipe(m(({active:s})=>s));return V([i,n]).pipe(m(([s,a])=>!(s&&a)),Q(),W(o.pipe(Pe(1))),ae(!0),bt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),ws(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))}function $i({document$:e,viewport$:t}){e.pipe(b(()=>A(".md-ellipsis")),J(r=>Ct(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),ye(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,pt(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),_(()=>n.removeAttribute("title")))})).subscribe(),e.pipe(b(()=>A(".md-status")),J(r=>pt(r,{viewport$:t}))).subscribe()}function Ri({document$:e,tablet$:t}){e.pipe(b(()=>A(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ts(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Pi({document$:e}){e.pipe(b(()=>A("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ts),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ii({viewport$:e,tablet$:t}){V([Be("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(rt(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ss(){return location.protocol==="file:"?_t(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):Ge(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var at=on(),Kt=dn(),$t=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),ji=Wt("(min-width: 1220px)"),Ui=gn(),Or=we(),Wi=document.forms.namedItem("search")?Ss():Ze,lo=new w;pi({alert$:lo});ci({document$:at});var mo=new w,Di=kt(Or.base);B("navigation.instant")&&ui({sitemap$:Di,location$:Kt,viewport$:He,progress$:mo}).subscribe(at);var Fi;((Fi=Or.version)==null?void 0:Fi.provider)==="mike"&&xi({document$:at});O(Kt,$t).pipe(rt(125)).subscribe(()=>{nt("drawer",!1),nt("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&&it(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&&it(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});$i({viewport$:He,document$:at});Ri({document$:at,tablet$:Lr});Pi({document$:at});Ii({viewport$:He,tablet$:Lr});var lt=ti(Ce("header"),{viewport$:He}),qt=at.pipe(m(()=>Ce("main")),b(e=>ni(e,{viewport$:He,header$:lt})),X(1)),Os=O(...me("consent").map(e=>Mn(e,{target$:$t})),...me("dialog").map(e=>Zn(e,{alert$:lo})),...me("header").map(e=>ri(e,{viewport$:He,header$:lt,main$:qt})),...me("palette").map(e=>ii(e)),...me("progress").map(e=>ai(e,{progress$:mo})),...me("search").map(e=>Si(e,{index$:Wi,keyboard$:po})),...me("source").map(e=>Ai(e))),Ls=k(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Xn(e,{sitemap$:Di,viewport$:He,target$:$t,print$:Ui})),...me("content").map(e=>B("search.highlight")?Oi(e,{index$:Wi,location$:Kt}):x),...me("header-title").map(e=>oi(e,{viewport$:He,header$:lt})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(ji,()=>co(e,{viewport$:He,header$:lt,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:lt,main$:qt}))),...me("tabs").map(e=>Ci(e,{viewport$:He,header$:lt})),...me("toc").map(e=>Hi(e,{viewport$:He,header$:lt,main$:qt,target$:$t})),...me("top").map(e=>ki(e,{viewport$:He,header$:lt,main$:qt,target$:$t})))),Ni=at.pipe(b(()=>Ls),Ne(Os),X(1));Ni.subscribe();window.document$=at;window.location$=Kt;window.target$=$t;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=ji;window.print$=Ui;window.alert$=lo;window.progress$=mo;window.component$=Ni;})(); + `):"",this.name="UnsubscriptionError",this.errors=r}});function Xe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var ze=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Oe(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(P(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Oe(f),d=u.next();!d.done;d=u.next()){var g=d.value;try{wo(g)}catch(L){i=i!=null?i:[],L instanceof Xt?i=B(B([],q(i)),q(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Xe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Xe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var $r=ze.EMPTY;function Zt(e){return e instanceof ze||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function wo(e){P(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var yt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?$r:(this.currentObservers=null,a.push(r),new ze(function(){o.currentObservers=null,Xe(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(I);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:$r},t}(w);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(w);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(St);var $o=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(Ot);var Dr=new $o(ko);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Tt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(Tt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(St);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ot);var ge=new Po(Ro);var x=new I(function(e){return e.complete()});function rr(e){return e&&P(e.schedule)}function Nr(e){return e[e.length-1]}function ct(e){return P(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return P(e==null?void 0:e.then)}function ir(e){return P(e[wt])}function ar(e){return Symbol.asyncIterator&&P(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ca(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=ca();function pr(e){return P(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ut(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ut(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ut(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return P(e==null?void 0:e.getReader)}function U(e){if(e instanceof I)return e;if(e!=null){if(ir(e))return pa(e);if(Lt(e))return la(e);if(nr(e))return ma(e);if(ar(e))return Io(e);if(pr(e))return fa(e);if(mr(e))return ua(e)}throw sr(e)}function pa(e){return new I(function(t){var r=e[wt]();if(P(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function la(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,Ee(1),r?rt(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return x}:y(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new w}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,g=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,g=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return y(function(H,ft){d++,!L&&!g&&ee();var Fe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!g&&(f=Br(Z,c))}),Fe.subscribe(ft),!l&&d>0&&(l=new ht({next:function(R){return Fe.next(R)},error:function(R){L=!0,ee(),f=Br(ne,n,R),Fe.error(R)},complete:function(){g=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function M(e,t=document){return Array.from(t.querySelectorAll(e))}function F(e,t=document){let r=ue(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ue(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var Ha=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),K(void 0),m(()=>Ve()||document.body),X(1));function Ke(e){return Ha.pipe(m(t=>e.contains(t)),Y())}function nt(e,t){return k(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>ke(+!r*t)):be,K(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function At(e){let t=S("script",{src:e});return k(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),Ee(1))))}var an=new w,ka=k(()=>typeof ResizeObserver=="undefined"?At("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(et,$(e)).pipe(A(()=>e.disconnect()))),X(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(T(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),A(()=>r.unobserve(t)))),m(()=>de(e)),K(de(e)))}function Ct(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Qe(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe($e(0,ge),m(()=>Qe(e)),K(Qe(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ye(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe($e(0,ge),m(()=>gr(e)),K(gr(e)))}var ln=new w,$a=k(()=>$(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(et,$(e)).pipe(A(()=>e.disconnect()))),X(1));function lt(e){return $a.pipe(T(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ye(e).pipe(m(({y:r})=>{let o=de(e),n=Ct(e);return r>=n.height-o.height-t}),Y())}var xr={drawer:F("[data-md-toggle=drawer]"),search:F("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function it(e,t){xr[e].checked!==t&&xr[e].click()}function Be(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),K(t.checked))}function Ra(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(K(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Ra(o,r)}return!0}),le());return Pa().pipe(b(t=>t?x:e))}function we(){return new URL(location.href)}function at(e,t=!1){if(Q("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new w}function hn(){return location.hash.slice(1)}function bn(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),K(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>ue(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(K(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(K(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():x))}function to(e,t){return new I(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ge(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),K(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),K(wn()))}function Sn(){return V([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=V([o,r]).pipe(m(()=>Qe(e)));return V([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Ia(e){return h(e,"message",t=>t.data)}function Fa(e){let t=new w;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Ia(t),o=Fa(t),n=new w;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var ja=F("#__config"),Ht=JSON.parse(ja.textContent);Ht.base=`${new URL(Ht.base,we())}`;function Te(){return Ht}function Q(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return F(`[data-md-component=${e}]`,t)}function me(e,t=document){return M(`[data-md-component=${e}]`,t)}function Ua(e){let t=F(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>F(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!Q("announce.dismiss")||!e.childElementCount)return x;if(!e.hidden){let t=F(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return k(()=>{let t=new w;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Ua(e).pipe(T(r=>t.next(r)),A(()=>t.complete()),m(r=>j({ref:e},r)))})}function Wa(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new w;return r.subscribe(({hidden:o})=>{e.hidden=o}),Wa(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))}function Dt(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return S("div",{class:"md-tooltip2",role:"dialog"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return S("div",{class:"md-tooltip2",role:"tooltip"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function Cn(e){return S("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return S("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function kn(){return S("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=Te(),s=new URL(e.location,i.base);Q("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=Te();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function $n(e){let t=e[0].score,r=[...e],o=Te(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function Rn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function Da(e){let t=Te(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function In(e,t){return e=e.filter(r=>{var o;return!((o=r.properties)!=null&&o.hidden)}),S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":Me("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(Da)))}var Na=0;function Va(e,t=250){let r=V([Ke(e),nt(e,t)]).pipe(m(([n,i])=>n||i),Y()),o=k(()=>sn(e)).pipe(J(Ye),gt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>V([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Na++}`;return k(()=>{let s=new w,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>ke(+!l*250,Dr)),Y(),b(l=>l?o:x),T(l=>l.id=i),le());V([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>nt(l,250)),K(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),g=d.width/2;if(f.role==="tooltip")return{x:g,y:8+d.height};if(d.y>=u.height/2){let{height:L}=de(f);return{x:g,y:-16-L}}else return{x:g,y:16+d.height}}));return V([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=de(F(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Y(),xe(ge),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),V([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Va(e,r).pipe(T(l=>s.next(l)),A(()=>s.complete()),m(l=>j({ref:e},l)))})}function Je(e,{viewport$:t},r=document.body){return Nt(e,{content$:new I(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function za(e,t){let r=k(()=>V([pn(e),Ye(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=de(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ke(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),Ee(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return k(()=>{let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),lt(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe($e(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),ot(125)).subscribe(()=>e.focus()),za(e,t).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function qa(e){let t=Te();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return M(r.join(", "),e)}function Ka(e){let t=[];for(let r of qa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ka(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ue(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?x:k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([F(".md-typeset",f),F(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(A(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return k(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):x})}var Nn=Gt(io());var Qa=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(K(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ya(e){return Le(e).pipe(m(({width:t})=>({scrollable:Ct(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=k(()=>{let n=new w,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Qa++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||Q("content.code.annotate"))){let g=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Y(),b(L=>L?g:x)))}}let u=M(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||Q("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),g=Hn();s.push(g),Q("content.tooltips")&&l.push(Je(g,{viewport$}));let L=h(g,"click").pipe(Ut(R=>!R,!1),T(()=>g.blur()),le());L.subscribe(R=>{g.classList.toggle("md-code__button--active",R)});let ee=fe(u).pipe(J(R=>nt(R).pipe(m(se=>[R,se]))));L.pipe(b(R=>R?ee:x)).subscribe(([R,se])=>{let ce=ue(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let ne=fe(u).pipe(J(R=>h(R,"mousedown").pipe(T(se=>se.preventDefault()),m(()=>R)))),Z=L.pipe(b(R=>R?ne:x),te(Dn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Se=M(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Se),Math.max(ce,...Se)]}})),H=Zr(x).pipe(v(R=>R.startsWith(`__codelineno-${p}-`)));H.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Se=>+Se-d+1);ce.length===1&&ce.push(ce[0]);for(let Se of M(".hll:not(.select)",e))Se.replaceWith(...Array.from(Se.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Se of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Se.childNodes).slice(1)),Se.append(je)}}),H.pipe(Ee(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=fe(M('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(T(se=>se.preventDefault()),m(()=>R)))).pipe(W(i),te(Dn),m(([R,se])=>{let he=+F(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Se=M(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Se),Math.max(he,...Se)]}}));O(Z,Fe).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||Q("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),Q("content.tooltips")&&l.push(Je(d,{viewport$}))}if(s.length){let d=kn();d.append(...s),a.insertBefore(d,e)}return Ya(e).pipe(T(d=>n.next(d)),A(()=>n.complete()),m(d=>j({ref:e},d)),Ne(O(...l).pipe(W(i))))});return Q("content.lazy")?lt(e).pipe(v(n=>n),Ee(1),b(()=>o)):o}function Ba(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return k(()=>{let r=new w;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ba(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function Ga(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Ja(e,t){for(let r of M("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}return $(e)}function Kn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return x;if(!(Q("navigation.instant.preview")||e.hasAttribute("data-preview")))return x;let o=V([Ke(e),nt(e)]).pipe(m(([i,s])=>i||s),Y(),v(i=>i));return bt([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?$(s):x}),b(i=>yr(i).pipe(b(s=>Ja(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=ue(s,i);return typeof a=="undefined"?x:$(Ga(a))})).pipe(b(i=>{let s=new I(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,j({content$:s},t))}))}var Qn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,Za=0;function es(){return typeof mermaid=="undefined"||mermaid instanceof Element?At("https://unpkg.com/mermaid@10/dist/mermaid.min.js"):$(void 0)}function Yn(e){return e.classList.remove("mermaid"),ao||(ao=es().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Qn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Za++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Bn=S("table");function Gn(e){return e.replaceWith(Bn),Bn.replaceWith(Pn(e)),$({ref:e})}function ts(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>F(`label[for="${r.id}"]`))))).pipe(K(F(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Jn(e,{viewport$:t,target$:r}){let o=F(".tabbed-labels",e),n=M(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),k(()=>{let a=new w,c=a.pipe(re(),ae(!0));V([a,Le(e)]).pipe(W(c),$e(1,ge)).subscribe({next([{active:p},l]){let f=Qe(p),{width:u}=de(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),V([Ye(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=Ct(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=de(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=F(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return Q("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let g of M("[data-tabs]"))for(let L of M(":scope > input",g)){let ee=F(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of M("audio, video",e))p.pause()}),lt(e).pipe(b(()=>ts(n)),T(p=>a.next(p)),A(()=>a.complete()),m(p=>j({ref:e},p)))}).pipe(Ze(pe))}function Xn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...M(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...M("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...M("a:not([title])",e).map(i=>Kn(i,t)),...M("pre.mermaid",e).map(i=>Yn(i)),...M("table:not([class])",e).map(i=>Gn(i)),...M("details",e).map(i=>qn(i,{target$:o,print$:n})),...M("[data-tabs]",e).map(i=>Jn(i,{viewport$:r,target$:o})),...M("[title]",e).filter(()=>Q("content.tooltips")).map(i=>Je(i,{viewport$:r})),...M(".footnote-ref",e).filter(()=>Q("content.footnote.tooltips")).map(i=>Nt(i,{content$:new I(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function rs(e,{alert$:t}){return t.pipe(b(r=>O($(!0),$(!1).pipe(ot(2e3))).pipe(m(o=>({message:r,active:o})))))}function Zn(e,t){let r=F(".md-typeset",e);return k(()=>{let o=new w;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),rs(e,t).pipe(T(n=>o.next(n)),A(()=>o.complete()),m(n=>j({ref:e},n)))})}var os=0;function ns(e,t){document.body.append(e);let{width:r}=de(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ye(o):$({x:0,y:0}),i=O(Ke(t),nt(t)).pipe(Y());return V([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Qe(t),l=de(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ei(e){let t=e.title;if(!t.length)return x;let r=`__tooltip_${os++}`,o=Dt(r,"inline"),n=F(".md-typeset",o);return n.innerHTML=t,k(()=>{let i=new w;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe($e(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),ns(o,e).pipe(T(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))}).pipe(Ze(pe))}function is({viewport$:e}){if(!Q("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),tt(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=Be("search");return V([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:$(!1)),K(!1))}function ti(e,t){return k(()=>V([Le(e),is(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function ri(e,{header$:t,main$:r}){return k(()=>{let o=new w,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(M("[title]",e)).pipe(v(()=>Q("content.tooltips")),J(s=>ei(s)));return r.subscribe(o),t.pipe(W(n),m(s=>j({ref:e},s)),Ne(i.pipe(W(n))))})}function as(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=de(e);return{active:o>=n}}),oe("active"))}function oi(e,t){return k(()=>{let r=new w;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ue(".md-content h1");return typeof o=="undefined"?x:as(o,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))})}function ni(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return V([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function ss(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),K(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ii(e){let t=M("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return k(()=>{let i=new w;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),ss(t).pipe(W(n.pipe(Pe(1))),vt(),T(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))})}function ai(e,{progress$:t}){return k(()=>{let r=new w;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}function si(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function cs(e,t){let r=new Map;for(let o of M("url",e)){let n=F("loc",o),i=[si(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of M("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(si(new URL(a),t))}}return r}function kt(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>cs(t,new URL(e))),ye(()=>$(new Map)),le())}function ci({document$:e}){let t=new Map;e.pipe(b(()=>M("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>kt(r).pipe(m(o=>[r,o]),ye(()=>x)))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(`${f}/`));if(typeof n=="undefined")return x;let[i,s]=n,a=we();if(a.href.startsWith(i))return x;let c=Te(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),$(l)}}return x})).subscribe(r=>at(r,!0))}var so=Gt(io());function ps(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function pi({alert$:e}){so.default.isSupported()&&new I(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ps(F(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function li(e,t){if(!(e.target instanceof Element))return x;let r=e.target.closest("a");if(r===null)return x;if(r.target||e.metaKey||e.ctrlKey)return x;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(r)):x}function mi(e){let t=new Map;for(let r of M(":scope > *",e.head))t.set(r.outerHTML,r);return t}function fi(e){for(let t of M("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function ls(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...Q("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=ue(o),i=ue(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=mi(document);for(let[o,n]of mi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return qe(M("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new I(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),x}),re(),ae(document))}function ui({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return x;$(document).subscribe(fi);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>li(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(we),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(ye(()=>(at(a,!0),x)))),b(fi),b(ls),le());return O(s.pipe(te(t,(a,c)=>c)),t.pipe(oe("pathname"),b(()=>t),oe("hash")),t.pipe(Y((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),T(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),Q("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>li(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),Ee(1))})).subscribe(a=>a.remove()),s}var bi=Gt(hi());function vi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,bi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function gi(e,t){let r=On(e);return O($(location.protocol!=="file:"),Be("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:Q("search.suggest")}}})),r}function xi({document$:e}){let t=Te(),r=Ge(new URL("../versions.json",t.base)).pipe(ye(()=>x)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?x:(i.preventDefault(),$(c))}}return x}),b(i=>kt(new URL(i)).pipe(m(s=>{let c=we().href.replace(t.base,i);return s.has(c.split("#")[0])?new URL(c):new URL(i)})))))).subscribe(n=>at(n,!0)),V([r,o]).subscribe(([n,i])=>{F(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function hs(e,{worker$:t}){let{searchParams:r}=we();r.has("q")&&(it("search",!0),e.value=r.get("q"),e.focus(),Be("search").pipe(Re(i=>!i)).subscribe(()=>{let i=we();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ke(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Y());return V([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function yi(e,{worker$:t}){let r=new w,o=r.pipe(re(),ae(!0));V([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&it("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=F("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),hs(e,{worker$:t}).pipe(T(i=>r.next(i)),A(()=>r.complete()),m(i=>j({ref:e},i)),X(1))}function Ei(e,{worker$:t,query$:r}){let o=new w,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=F(":scope > :first-child",e),a=F(":scope > :last-child",e);Be("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),b(({items:l})=>O($(...l.slice(0,10)),$(...l.slice(10)).pipe(tt(4),Xr(n),b(([f])=>f)))),m($n),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=ue("details",l);return typeof f=="undefined"?x:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),A(()=>o.complete()),m(l=>j({ref:e},l)))}function bs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=we();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function wi(e,t){let r=new w,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),bs(e,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))}function Ti(e,{worker$:t,keyboard$:r}){let o=new w,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Y());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Si(e,{index$:t,keyboard$:r}){let o=Te();try{let n=gi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>it("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of M(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":it("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...M(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=yi(i,{worker$:n});return O(a,Ei(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>wi(c,{query$:a})),...me("search-suggest",e).map(c=>Ti(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,et}}function Oi(e,{index$:t,location$:r}){return V([t,r.pipe(K(we()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>vi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function vs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return V([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=F(".md-sidebar__scrollwrap",e),{y:s}=Qe(i);return k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=a.pipe($e(0,ge));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of M(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2})}}}),fe(M("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),W(c)))).subscribe(l=>{let f=F(`[id="${l.htmlFor}"]`);F(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),Q("content.tooltips")&&fe(M("abbr[title]",e)).pipe(J(l=>Je(l,{viewport$})),W(c)).subscribe(),vs(e,r).pipe(T(l=>a.next(l)),A(()=>a.complete()),m(l=>j({ref:e},l)))})}function Li(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return bt(Ge(`${r}/releases/latest`).pipe(ye(()=>x),m(o=>({version:o.tag_name})),rt({})),Ge(r).pipe(ye(()=>x),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),rt({}))).pipe(m(([o,n])=>j(j({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(m(o=>({repositories:o.public_repos})),rt({}))}}function Mi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(ye(()=>x),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),rt({}))}function _i(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Li(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Mi(r,o)}return x}var gs;function xs(e){return gs||(gs=k(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return x}return _i(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(ye(()=>x),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ai(e){let t=F(":scope > :last-child",e);return k(()=>{let r=new w;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),xs(e).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function ys(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Ci(e,t){return k(()=>{let r=new w;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(Q("navigation.tabs.sticky")?$({hidden:!1}):ys(e,t)).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){let o=new Map,n=M(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ue(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=F(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>k(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let g=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!g)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),K({prev:[],next:[]}),tt(2,1),m(([a,c])=>a.prev.length{let i=new w,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),Q("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return Q("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),vt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=we(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Es(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function ws(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),tt(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return V([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),W(o.pipe(Pe(1))),ae(!0),vt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),ws(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))}function $i({document$:e,viewport$:t}){e.pipe(b(()=>M(".md-ellipsis")),J(r=>lt(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),Ee(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,Je(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),A(()=>n.removeAttribute("title")))})).subscribe(),e.pipe(b(()=>M(".md-status")),J(r=>Je(r,{viewport$:t}))).subscribe()}function Ri({document$:e,tablet$:t}){e.pipe(b(()=>M(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ts(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Pi({document$:e}){e.pipe(b(()=>M("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ts),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ii({viewport$:e,tablet$:t}){V([Be("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(ot(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ss(){return location.protocol==="file:"?At(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):Ge(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var st=on(),Kt=dn(),$t=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),ji=Wt("(min-width: 1220px)"),Ui=gn(),Or=Te(),Wi=document.forms.namedItem("search")?Ss():et,lo=new w;pi({alert$:lo});ci({document$:st});var mo=new w,Di=kt(Or.base);Q("navigation.instant")&&ui({sitemap$:Di,location$:Kt,viewport$:He,progress$:mo}).subscribe(st);var Fi;((Fi=Or.version)==null?void 0:Fi.provider)==="mike"&&xi({document$:st});O(Kt,$t).pipe(ot(125)).subscribe(()=>{it("drawer",!1),it("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ue("link[rel=prev]");typeof t!="undefined"&&at(t);break;case"n":case".":let r=ue("link[rel=next]");typeof r!="undefined"&&at(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});$i({viewport$:He,document$:st});Ri({document$:st,tablet$:Lr});Pi({document$:st});Ii({viewport$:He,tablet$:Lr});var mt=ti(Ce("header"),{viewport$:He}),qt=st.pipe(m(()=>Ce("main")),b(e=>ni(e,{viewport$:He,header$:mt})),X(1)),Os=O(...me("consent").map(e=>Mn(e,{target$:$t})),...me("dialog").map(e=>Zn(e,{alert$:lo})),...me("header").map(e=>ri(e,{viewport$:He,header$:mt,main$:qt})),...me("palette").map(e=>ii(e)),...me("progress").map(e=>ai(e,{progress$:mo})),...me("search").map(e=>Si(e,{index$:Wi,keyboard$:po})),...me("source").map(e=>Ai(e))),Ls=k(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Xn(e,{sitemap$:Di,viewport$:He,target$:$t,print$:Ui})),...me("content").map(e=>Q("search.highlight")?Oi(e,{index$:Wi,location$:Kt}):x),...me("header-title").map(e=>oi(e,{viewport$:He,header$:mt})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(ji,()=>co(e,{viewport$:He,header$:mt,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:mt,main$:qt}))),...me("tabs").map(e=>Ci(e,{viewport$:He,header$:mt})),...me("toc").map(e=>Hi(e,{viewport$:He,header$:mt,main$:qt,target$:$t})),...me("top").map(e=>ki(e,{viewport$:He,header$:mt,main$:qt,target$:$t})))),Ni=st.pipe(b(()=>Ls),Ne(Os),X(1));Ni.subscribe();window.document$=st;window.location$=Kt;window.target$=$t;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=ji;window.print$=Ui;window.alert$=lo;window.progress$=mo;window.component$=Ni;})(); diff --git a/0.25.3/assets/stylesheets/main.d5b5f0fd.min.css b/0.25.3/assets/stylesheets/main.46e89654.min.css similarity index 79% rename from 0.25.3/assets/stylesheets/main.d5b5f0fd.min.css rename to 0.25.3/assets/stylesheets/main.46e89654.min.css index 17f5e1789..621427735 100644 --- a/0.25.3/assets/stylesheets/main.d5b5f0fd.min.css +++ b/0.25.3/assets/stylesheets/main.46e89654.min.css @@ -1 +1 @@ -@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:1fr;opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:1fr;opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:#0000008a;cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem #0000;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:#00000042;border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:#ffffff1f}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem #00000012;color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:#0000;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::placeholder{transition:color .25s}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:#0000}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{-webkit-backface-visibility:hidden;backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:block}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:1fr;opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:1fr;opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:#0000008a;cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem #0000;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:#00000042;border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:#ffffff1f}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem #00000012;color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:#0000;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::placeholder{transition:color .25s}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:#0000}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{-webkit-backface-visibility:hidden;backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/0.25.3/built-in-features/aws-ec2-connect/index.html b/0.25.3/built-in-features/aws-ec2-connect/index.html index bb468f9bf..637004d3c 100644 --- a/0.25.3/built-in-features/aws-ec2-connect/index.html +++ b/0.25.3/built-in-features/aws-ec2-connect/index.html @@ -1,4 +1,4 @@ - Configure AWS EC2 Connect - Leapp - Docs

EC2 connect through AWS SSM

What is AWS EC2 Connect

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

How To configure AWS EC2 Connect in Leapp

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS
example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.

Video tutorial

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

\ No newline at end of file +

EC2 connect through AWS SSM

What is AWS EC2 Connect

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

How To configure AWS EC2 Connect in Leapp

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS
example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.

Video tutorial

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

\ No newline at end of file diff --git a/0.25.3/built-in-features/aws-named-profiles/index.html b/0.25.3/built-in-features/aws-named-profiles/index.html index 93d52ecf4..374aaa076 100644 --- a/0.25.3/built-in-features/aws-named-profiles/index.html +++ b/0.25.3/built-in-features/aws-named-profiles/index.html @@ -1,4 +1,4 @@ - Configure Named Profiles - Leapp - Docs

AWS Multi-profile management

What is a Named Profile

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

How to configure a Named Profile in Leapp

Named Profiles can be created in 3 ways:

Click on the gear icon Screenshot 2022-02-03 at 15 22 34 and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.


Screenshot 2022-02-03 at 15 25 43

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the "Change Profile" option in the session list.

Named Profile List

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the Screenshot 2022-02-03 at 15 32 11 button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

\ No newline at end of file +

AWS Multi-profile management

What is a Named Profile

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

How to configure a Named Profile in Leapp

Named Profiles can be created in 3 ways:

Click on the gear icon Screenshot 2022-02-03 at 15 22 34 and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.


Screenshot 2022-02-03 at 15 25 43

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the "Change Profile" option in the session list.

Named Profile List

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the Screenshot 2022-02-03 at 15 32 11 button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

\ No newline at end of file diff --git a/0.25.3/built-in-features/general-options/index.html b/0.25.3/built-in-features/general-options/index.html index 46c0a8448..cabd690ae 100644 --- a/0.25.3/built-in-features/general-options/index.html +++ b/0.25.3/built-in-features/general-options/index.html @@ -1 +1 @@ - General Options - Leapp - Docs

General Options

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

Default Regions

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

Terminal Selection

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

Color Theme

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

Default Webconsole Duration

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

\ No newline at end of file + General Options - Leapp - Docs

General Options

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

Default Regions

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

Terminal Selection

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

Color Theme

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

Default Webconsole Duration

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

\ No newline at end of file diff --git a/0.25.3/built-in-features/multi-console/index.html b/0.25.3/built-in-features/multi-console/index.html index 2fabecc04..2d2be964c 100644 --- a/0.25.3/built-in-features/multi-console/index.html +++ b/0.25.3/built-in-features/multi-console/index.html @@ -1,4 +1,4 @@ - Configure Multi Console - Leapp - Docs

Multi-Console Browser Extension

What is Multi Console

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

List of Supported Browsers

Browser Supported
Firefox ✅
Chrome ✅
Edge ✅
Brave ✅
Safari ❌

How to Configure Multi Console in Leapp

Install the Extension

Firefox

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox ⇩

Chrome, Edge and other Chromium based browsers

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others ⇩

Uninstall the Extension

Firefox

  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove

Chrome, Edge and other Chromium based browsers

  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select "Cookies". Then, remove all cookies by clicking "Remove" until the cookie list is empty and finally click on Done

uninstall extension step 1 uninstall extension step 2

How to use it

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option
enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).


By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui
leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

\ No newline at end of file +

Multi-Console Browser Extension

What is Multi Console

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

List of Supported Browsers

Browser Supported
Firefox ✅
Chrome ✅
Edge ✅
Brave ✅
Safari ❌

How to Configure Multi Console in Leapp

Install the Extension

Firefox

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox ⇩

Chrome, Edge and other Chromium based browsers

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others ⇩

Uninstall the Extension

Firefox

  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove

Chrome, Edge and other Chromium based browsers

  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select "Cookies". Then, remove all cookies by clicking "Remove" until the cookie list is empty and finally click on Done

uninstall extension step 1 uninstall extension step 2

How to use it

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option
enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).


By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui
leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

\ No newline at end of file diff --git a/0.25.3/built-in-features/opening-web-console/index.html b/0.25.3/built-in-features/opening-web-console/index.html index 3ce5dcb82..830861413 100644 --- a/0.25.3/built-in-features/opening-web-console/index.html +++ b/0.25.3/built-in-features/opening-web-console/index.html @@ -1,4 +1,4 @@ - Configure Open Web Console - Leapp - Docs

Opening AWS Web Console

What is Open Web Console

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

How to Configure Open Web Console in Leapp

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

\ No newline at end of file +

Opening AWS Web Console

What is Open Web Console

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

How to Configure Open Web Console in Leapp

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

\ No newline at end of file diff --git a/0.25.3/cli/index.html b/0.25.3/cli/index.html index 94f5be6ce..aa695a449 100644 --- a/0.25.3/cli/index.html +++ b/0.25.3/cli/index.html @@ -1,4 +1,4 @@ - Index - Leapp - Docs

Index

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli
+ Index - Leapp - Docs      

Index

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli
 $ leapp COMMAND
 running command...
 $ leapp (--version)
@@ -7,4 +7,4 @@
 USAGE
   $ leapp COMMAND
 ...
-

Command Topics

\ No newline at end of file +

Command Topics

\ No newline at end of file diff --git a/0.25.3/cli/scopes/help/index.html b/0.25.3/cli/scopes/help/index.html index 440266ebc..b64baca9d 100644 --- a/0.25.3/cli/scopes/help/index.html +++ b/0.25.3/cli/scopes/help/index.html @@ -1,4 +1,4 @@ - Help - Leapp - Docs

leapp help

Display help for leapp.

leapp help [COMMANDS]

Display help for leapp.

USAGE
+ Help - Leapp - Docs      

leapp help

Display help for leapp.

leapp help [COMMANDS]

Display help for leapp.

USAGE
   $ leapp help [COMMANDS] [-n]
 
 ARGUMENTS
@@ -9,4 +9,4 @@
 
 DESCRIPTION
   Display help for leapp.
-

See code: @oclif/plugin-help

\ No newline at end of file +

See code: @oclif/plugin-help

\ No newline at end of file diff --git a/0.25.3/cli/scopes/idp-url/index.html b/0.25.3/cli/scopes/idp-url/index.html index f9b6d905b..7e1a234fb 100644 --- a/0.25.3/cli/scopes/idp-url/index.html +++ b/0.25.3/cli/scopes/idp-url/index.html @@ -1,4 +1,4 @@ - Idp Url - Leapp - Docs

leapp idp-url

SAML 2.0 Identity providers URL management

leapp idp-url create

Create a new identity provider URL

USAGE
+ Idp Url - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/integration/index.html b/0.25.3/cli/scopes/integration/index.html index 6eac1dee2..c281727b5 100644 --- a/0.25.3/cli/scopes/integration/index.html +++ b/0.25.3/cli/scopes/integration/index.html @@ -1,4 +1,4 @@ - Integration - Leapp - Docs

leapp integration

Leapp Integrations management

leapp integration create

Create a new integration

USAGE
+ Integration - Leapp - Docs      

leapp integration

Leapp Integrations management

leapp integration create

Create a new integration

USAGE
   $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]
     [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]
 
@@ -92,4 +92,4 @@
   $leapp integration sync
 
   $leapp integration sync --integrationId ID
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/profile/index.html b/0.25.3/cli/scopes/profile/index.html index c8faa183e..87a7f2c3f 100644 --- a/0.25.3/cli/scopes/profile/index.html +++ b/0.25.3/cli/scopes/profile/index.html @@ -1,4 +1,4 @@ - Profile - Leapp - Docs

leapp profile

Leapp AWS Multi-profile management

leapp profile create

Create a new AWS named profile

USAGE
+ Profile - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/region/index.html b/0.25.3/cli/scopes/region/index.html index 23483d039..168c1e75c 100644 --- a/0.25.3/cli/scopes/region/index.html +++ b/0.25.3/cli/scopes/region/index.html @@ -1,4 +1,4 @@ - Region - Leapp - Docs

leapp region

Leapp regions management

leapp region get-default

Displays the default region

USAGE
+ Region - Leapp - Docs      

leapp region

Leapp regions management

leapp region get-default

Displays the default region

USAGE
   $ leapp region get-default
 
 DESCRIPTION
@@ -19,4 +19,4 @@
   $leapp region set-default
 
   $leapp region set-default --region AWSREGION
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/session/index.html b/0.25.3/cli/scopes/session/index.html index c9c73b93d..d0341329b 100644 --- a/0.25.3/cli/scopes/session/index.html +++ b/0.25.3/cli/scopes/session/index.html @@ -1,4 +1,4 @@ - Session - Leapp - Docs

leapp session

Sessions management

leapp session add

Add a new session

USAGE
+ Session - Leapp - Docs      

leapp session

Sessions management

leapp session add

Add a new session

USAGE
   $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]
     [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]
     [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType
@@ -242,4 +242,4 @@
   $leapp session stop SESSIONNAME --noInteractive
 
   $leapp session stop --sessionId SESSIONID
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/set-workspace/index.html b/0.25.3/cli/scopes/set-workspace/index.html index 6f006e375..d86b2055b 100644 --- a/0.25.3/cli/scopes/set-workspace/index.html +++ b/0.25.3/cli/scopes/set-workspace/index.html @@ -1,4 +1,4 @@ - Set Workspace - Leapp - Docs

leapp set-workspace

Set the current Leapp workspace

leapp set-workspace [WORKSPACENAME]

Set the current Leapp workspace

USAGE
+ Set Workspace - Leapp - Docs      

leapp set-workspace

Set the current Leapp workspace

leapp set-workspace [WORKSPACENAME]

Set the current Leapp workspace

USAGE
   $ leapp set-workspace [WORKSPACENAME]
 
 ARGUMENTS
@@ -13,4 +13,4 @@
   $leapp team set-workspace local
 
   $leapp team set-workspace WORKSPACE-NAME
-

See code: dist/commands/set-workspace.ts

\ No newline at end of file +

See code: dist/commands/set-workspace.ts

\ No newline at end of file diff --git a/0.25.3/cli/scopes/team/index.html b/0.25.3/cli/scopes/team/index.html index 8b8cc4ff5..ca1192a4e 100644 --- a/0.25.3/cli/scopes/team/index.html +++ b/0.25.3/cli/scopes/team/index.html @@ -1,4 +1,4 @@ - Team - Leapp - Docs

leapp team

Login to your Team account

leapp team login

Login to your Team account

USAGE
+ Team - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/cli/scopes/version/index.html b/0.25.3/cli/scopes/version/index.html index 641f0998d..2dc74b750 100644 --- a/0.25.3/cli/scopes/version/index.html +++ b/0.25.3/cli/scopes/version/index.html @@ -1,4 +1,4 @@ - Version - Leapp - Docs

leapp version

Displays the Cli and Core versions

leapp version

Displays the Cli and Core versions

USAGE
+ Version - Leapp - Docs      

leapp version

Displays the Cli and Core versions

leapp version

Displays the Cli and Core versions

USAGE
   $ leapp version
 
 DESCRIPTION
@@ -6,4 +6,4 @@
 
 EXAMPLES
   $leapp version
-

See code: dist/commands/version.ts

\ No newline at end of file +

See code: dist/commands/version.ts

\ No newline at end of file diff --git a/0.25.3/cli/scopes/workspace/index.html b/0.25.3/cli/scopes/workspace/index.html index ada1474b9..f223628ef 100644 --- a/0.25.3/cli/scopes/workspace/index.html +++ b/0.25.3/cli/scopes/workspace/index.html @@ -1,4 +1,4 @@ - Workspace - Leapp - Docs

leapp workspace

Show the current workspace

leapp workspace

Show the current workspace

USAGE
+ Workspace - Leapp - Docs      

leapp workspace

Show the current workspace

leapp workspace

Show the current workspace

USAGE
   $ leapp workspace
 
 DESCRIPTION
@@ -6,4 +6,4 @@
 
 EXAMPLES
   $leapp workspace
-

See code: dist/commands/workspace.ts

\ No newline at end of file +

See code: dist/commands/workspace.ts

\ No newline at end of file diff --git a/0.25.3/configuration/index.html b/0.25.3/configuration/index.html index f4a684058..4ba77e158 100644 --- a/0.25.3/configuration/index.html +++ b/0.25.3/configuration/index.html @@ -1 +1 @@ - Add your first configuration - Leapp - Docs
\ No newline at end of file + Add your first configuration - Leapp - Docs
\ No newline at end of file diff --git a/0.25.3/configuring-integration/configure-aws-single-sign-on-integration/index.html b/0.25.3/configuring-integration/configure-aws-single-sign-on-integration/index.html index 5d8a3a04a..f37a2bc32 100644 --- a/0.25.3/configuring-integration/configure-aws-single-sign-on-integration/index.html +++ b/0.25.3/configuring-integration/configure-aws-single-sign-on-integration/index.html @@ -1 +1 @@ - Configure an AWS Identity Center (ex AWS Single Sign-On) integration - Leapp - Docs

Configure AWS Single Sign-On integration

What is AWS Identity Center (ex AWS Single Sign-On)

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as AWS Single Sign-on
AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start.
REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part.

Video tutorial

\ No newline at end of file + Configure an AWS Identity Center (ex AWS Single Sign-On) integration - Leapp - Docs

Configure AWS Single Sign-On integration

What is AWS Identity Center (ex AWS Single Sign-On)

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as AWS Single Sign-on
AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start.
REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part.

Video tutorial

\ No newline at end of file diff --git a/0.25.3/configuring-integration/configure-azure-integration/index.html b/0.25.3/configuring-integration/configure-azure-integration/index.html index e318ad584..ceb645783 100644 --- a/0.25.3/configuring-integration/configure-azure-integration/index.html +++ b/0.25.3/configuring-integration/configure-azure-integration/index.html @@ -1 +1 @@ - Configure an Azure integration - Leapp - Docs

Configure Azure integration

What is an Azure integration

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

How to configure an Azure integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as Azure
ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database.
LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options.

Video tutorial

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

\ No newline at end of file + Configure an Azure integration - Leapp - Docs

Configure Azure integration

What is an Azure integration

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

How to configure an Azure integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as Azure
ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database.
LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options.

Video tutorial

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

\ No newline at end of file diff --git a/0.25.3/configuring-session/configure-aws-iam-role-chained/index.html b/0.25.3/configuring-session/configure-aws-iam-role-chained/index.html index 40d5225ec..500404c18 100644 --- a/0.25.3/configuring-session/configure-aws-iam-role-chained/index.html +++ b/0.25.3/configuring-session/configure-aws-iam-role-chained/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM Role Chained - Leapp - Docs

Configure AWS IAM Role Chained

What is an AWS IAM Role Chained session

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

How to configure an AWS IAM Role Chained in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.
ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity.
ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp.

Video tutorial

\ No newline at end of file +

Configure AWS IAM Role Chained

What is an AWS IAM Role Chained session

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

How to configure an AWS IAM Role Chained in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.
ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity.
ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp.

Video tutorial

\ No newline at end of file diff --git a/0.25.3/configuring-session/configure-aws-iam-role-federated/index.html b/0.25.3/configuring-session/configure-aws-iam-role-federated/index.html index 5e79a8554..5bcd7ffa9 100644 --- a/0.25.3/configuring-session/configure-aws-iam-role-federated/index.html +++ b/0.25.3/configuring-session/configure-aws-iam-role-federated/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM Role Federated - Leapp - Docs

Configure AWS IAM Role Federated

What is an AWS IAM Role Federated session

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.

Supported SAML Identity Providers

Identity Provider AWS Azure
GSUITE ✅ ❌
OKTA ✅ ❌
ONELOGIN ✅ ❌
AZURE AD ✅ ✅
AUTH0 ✅ ❌
KEYCLOAK ✅ ❌
JUMPCLOUD ✅ ❌

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

How to configure an AWS IAM Role Federated in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider.
AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.

Video tutorial

\ No newline at end of file +

Configure AWS IAM Role Federated

What is an AWS IAM Role Federated session

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.

Supported SAML Identity Providers

Identity Provider AWS Azure
GSUITE ✅ ❌
OKTA ✅ ❌
ONELOGIN ✅ ❌
AZURE AD ✅ ✅
AUTH0 ✅ ❌
KEYCLOAK ✅ ❌
JUMPCLOUD ✅ ❌

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

How to configure an AWS IAM Role Federated in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider.
AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.

Video tutorial

\ No newline at end of file diff --git a/0.25.3/configuring-session/configure-aws-iam-user/index.html b/0.25.3/configuring-session/configure-aws-iam-user/index.html index a0e9293fc..360d4cfcb 100644 --- a/0.25.3/configuring-session/configure-aws-iam-user/index.html +++ b/0.25.3/configuring-session/configure-aws-iam-user/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM User - Leapp - Docs

Configure AWS IAM User

What is an AWS IAM User session

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

How to configure an AWS IAM User in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
MFA DEVICE Your MFA device ID to set up multi-factor authentication.
ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
Add AWS IAM User Screen
Add AWS IAM User Screen

Video tutorial

\ No newline at end of file +

Configure AWS IAM User

What is an AWS IAM User session

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

How to configure an AWS IAM User in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
MFA DEVICE Your MFA device ID to set up multi-factor authentication.
ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
Add AWS IAM User Screen
Add AWS IAM User Screen

Video tutorial

\ No newline at end of file diff --git a/0.25.3/configuring-session/configure-localstack/index.html b/0.25.3/configuring-session/configure-localstack/index.html index f86eb9beb..4b713fbe9 100644 --- a/0.25.3/configuring-session/configure-localstack/index.html +++ b/0.25.3/configuring-session/configure-localstack/index.html @@ -1,4 +1,4 @@ - Configure LocalStack - Leapp - Docs

Configure LocalStack

What is a LocalStack session

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

How to configure a LocalStack session in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

\ No newline at end of file +

Configure LocalStack

What is a LocalStack session

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

How to configure a LocalStack session in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

\ No newline at end of file diff --git a/0.25.3/contributing/get-involved/index.html b/0.25.3/contributing/get-involved/index.html index 53d1b6042..6de0360f8 100644 --- a/0.25.3/contributing/get-involved/index.html +++ b/0.25.3/contributing/get-involved/index.html @@ -1 +1 @@ - Get involved - Leapp - Docs

Get involved

Contributions and questions are not just welcome, they’re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you’re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you. 💙

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

\ No newline at end of file + Get involved - Leapp - Docs

Get involved

Contributions and questions are not just welcome, they’re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you’re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you. 💙

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

\ No newline at end of file diff --git a/0.25.3/edit-session/index.html b/0.25.3/edit-session/index.html index 0d4939e36..edd5dd293 100644 --- a/0.25.3/edit-session/index.html +++ b/0.25.3/edit-session/index.html @@ -1 +1 @@ - Editing a session - Leapp - Docs

Editing a session

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can’t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select "edit session". A new modal will appear, allowing the user to choose which parameters to change.

edit session
edit session

Below are the configuration options for every type of session:

Iam User

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault

IAM Role Chained

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing "Create Chained Session"

IAM Role Federated

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

How we handle Secrets when Editing a Session

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

\ No newline at end of file + Editing a session - Leapp - Docs

Editing a session

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can’t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select "edit session". A new modal will appear, allowing the user to choose which parameters to change.

edit session
edit session

Below are the configuration options for every type of session:

Iam User

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault

IAM Role Chained

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing "Create Chained Session"

IAM Role Federated

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

How we handle Secrets when Editing a Session

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

\ No newline at end of file diff --git a/0.25.3/index.html b/0.25.3/index.html index 02893ca71..f2434dca3 100644 --- a/0.25.3/index.html +++ b/0.25.3/index.html @@ -1 +1 @@ - Overview - Leapp - Docs

Overview

Welcome to Leapp 🚀

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window
Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

Introducing Leapp CLI

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

\ No newline at end of file + Overview - Leapp - Docs

Overview

Welcome to Leapp 🚀

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window
Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

Introducing Leapp CLI

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

\ No newline at end of file diff --git a/0.25.3/installation/install-leapp/index.html b/0.25.3/installation/install-leapp/index.html index 062673f33..9281410a3 100644 --- a/0.25.3/installation/install-leapp/index.html +++ b/0.25.3/installation/install-leapp/index.html @@ -1,5 +1,5 @@ - Install Leapp - Leapp - Docs

Install Leapp

Install Leapp App

MacOS, Windows, and Linux

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp ⇩

Unzip the package and double-click the executable to install.

macOS (Homebrew)

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp
+ Install Leapp - Leapp - Docs      

Install Leapp

Install Leapp App

MacOS, Windows, and Linux

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp ⇩

Unzip the package and double-click the executable to install.

macOS (Homebrew)

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp
 

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

Install Leapp CLI

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli
 

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli
 

Install Leapp CLI on macOS with ARM64 chip (M1, M2)

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64
-

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

\ No newline at end of file +

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

\ No newline at end of file diff --git a/0.25.3/installation/requirements/index.html b/0.25.3/installation/requirements/index.html index b97c0ee68..a77e6d152 100644 --- a/0.25.3/installation/requirements/index.html +++ b/0.25.3/installation/requirements/index.html @@ -1,4 +1,4 @@ - Requirements - Leapp - Docs

Requirements

MacOS and Windows

There are no requirements for macOS and Windows users.

Linux systems

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

sudo pacman -S gnome-keyring
+ Requirements - Leapp - Docs      

Requirements

MacOS and Windows

There are no requirements for macOS and Windows users.

Linux systems

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

sudo pacman -S gnome-keyring
 sudo pacman -S libsecret
 
sudo apt-get install gnome-keyring
 sudo apt-get install libsecret-1-dev
@@ -7,4 +7,4 @@
 

Logging into EC2 Instances via AWS SSM with Leapp

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>
 

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/
 

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/installation/update-leapp/index.html b/0.25.3/installation/update-leapp/index.html index b59e6905e..e7dcc8c38 100644 --- a/0.25.3/installation/update-leapp/index.html +++ b/0.25.3/installation/update-leapp/index.html @@ -1,3 +1,3 @@ - Update Leapp - Leapp - Docs

Update Leapp

Desktop App

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Leapp will close the modal and notify the user that a new update is available by adding a notification dot Screenshot_2021-05-04_at_10 28 21 (1) to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

CLI

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npm update -g @noovolari/leapp-cli
+ Update Leapp - Leapp - Docs      

Update Leapp

Desktop App

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Leapp will close the modal and notify the user that a new update is available by adding a notification dot Screenshot_2021-05-04_at_10 28 21 (1) to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

CLI

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npm update -g @noovolari/leapp-cli
 
brew upgrade Noovolari/brew/leapp-cli
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/integrations/index.html b/0.25.3/integrations/index.html index e3b15d02c..18139332b 100644 --- a/0.25.3/integrations/index.html +++ b/0.25.3/integrations/index.html @@ -1 +1 @@ - Integrations - Leapp - Docs

Integrations

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

Actions

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description
CREATE  Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions.
DELETE  Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.)
SYNC  Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status.
LOGOUT  Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it.

Supported Services

Service Supported
AWS SSO ✅
Okta Coming Soon
OneLogin Coming Soon
AzureAD ✅
\ No newline at end of file + Integrations - Leapp - Docs

Integrations

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

Actions

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description
CREATE  Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions.
DELETE  Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.)
SYNC  Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status.
LOGOUT  Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it.

Supported Services

Service Supported
AWS SSO ✅
Okta Coming Soon
OneLogin Coming Soon
AzureAD ✅
\ No newline at end of file diff --git a/0.25.3/leapp-pro/export-pro-workspace/index.html b/0.25.3/leapp-pro/export-pro-workspace/index.html index befb8fa5d..338b17c78 100644 --- a/0.25.3/leapp-pro/export-pro-workspace/index.html +++ b/0.25.3/leapp-pro/export-pro-workspace/index.html @@ -1,5 +1,5 @@ - Export PRO Workspace - Leapp - Docs

Export PRO Workspace

How to export your Pro Workspace

  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:
    + Export PRO Workspace - Leapp - Docs      

    Export PRO Workspace

    How to export your Pro Workspace

    1. create a backup of your ~/.Leapp/Leapp-lock.json file;
      // From ~/.Leapp directory run the following command:
       cp Leapp-lock.json Leapp-lock.json.bkp
       
    2. log into you Pro Workspace using the Desktop App;

    3. from the Leapp Options "General" tab, click the button next to the "Export Pro/Team workspace" label;

    4. close the Leapp Options dialog;

    5. close Leapp (on macOS ⌘+Q);
    6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
    7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
      rm Leapp-lock.json
       mv Leapp-lock.json.exported Leapp-lock.json
      -
    8. re-open Leapp;
    9. switch to the Local Workspace;
    10. you should now see your Pro Workspace migrated into the Local one.
    \ No newline at end of file +
  2. re-open Leapp;
  3. switch to the Local Workspace;
  4. you should now see your Pro Workspace migrated into the Local one.
\ No newline at end of file diff --git a/0.25.3/leapp-pro/getting-started/index.html b/0.25.3/leapp-pro/getting-started/index.html deleted file mode 100644 index 2fabfc2ac..000000000 --- a/0.25.3/leapp-pro/getting-started/index.html +++ /dev/null @@ -1 +0,0 @@ - Getting Started - Leapp - Docs

Getting Started

Why Leapp Pro?

Leapp Pro enable Users to protect their Cloud access with Username and password.

With Leapp Pro you can back up and synchronize your Leapp workspace and access to any device you want without losing your access configurations.

Getting started guide

Security and syncronization

Once you updgrade your Plan to Leapp Pro, your local Workspace will be moved to the Pro Workspace. All the data inside your workspace are secured with end-to-end encryption through your Master password.

\ No newline at end of file diff --git a/0.25.3/leapp-pro/getting-started/lock/index.html b/0.25.3/leapp-pro/getting-started/lock/index.html deleted file mode 100644 index e6aefcf56..000000000 --- a/0.25.3/leapp-pro/getting-started/lock/index.html +++ /dev/null @@ -1 +0,0 @@ - Lock your Workspace - Leapp - Docs

Lock your Workspace

Leapp Pro allows the user to temporary lock the workspace, making it accessible only by typing again your master-password. This feature provides a further security level on top of the standard Leapp Community edition.

How to lock the Leapp Pro workspace

To lock your Leapp Pro workspace you should click on the Workspace button located in the top-left area and select the Lock option.

Workspace button
Workspace button
Lock option
Lock option

The Leapp Pro lock screen should appear, prompting for your master-password.

Leapp Pro lock screen
Leapp Pro lock screen

Touch ID

You can also use your fingerprint to unlock Leapp if your PC is Touch ID compatible. After Logging to your Pro workspace for the first time, Leapp will associate your workspace with your system Touch ID. After that the option will be available and can also be tweaked in the general tab of the option menu.

Troubles in locking your Workspace

In case of any troubles locking Leapp Pro workspace please contact us.

\ No newline at end of file diff --git a/0.25.3/leapp-pro/getting-started/sign-in/index.html b/0.25.3/leapp-pro/getting-started/sign-in/index.html deleted file mode 100644 index 08506fdf1..000000000 --- a/0.25.3/leapp-pro/getting-started/sign-in/index.html +++ /dev/null @@ -1 +0,0 @@ - Sign-in - Leapp - Docs

Sign-in

With Leapp Pro you can always sign-in from any location, gaining instant access to your personal workspace.

Sign-in to Leapp Pro

After upgrading Leapp Community edition, you can sign-in at any time, just clicking on the Workspace button located in the top-left area and selecting the Sign-in Workspace option.

Workspace button
Workspace button
Sign-in Workspace option
Sign-in Workspace option

The Sign-in Workspace dialog will appear. Enter your Email address, master-password and click on the Add Workspace button.

Sign-in dialog
Sign-in dialog

If the information entered is correct, your Leapp Pro workspace will be displayed and you can immediately use it to manage your cloud credentials.

Leapp Pro Workspace
Leapp Pro Workspace

To avoid unwanted access, you can lock your Leapp Pro workspace at any time.

Troubles in signing in to Leapp Pro?

In case of any troubles signing in to Leapp Pro please contact us.

\ No newline at end of file diff --git a/0.25.3/leapp-pro/getting-started/sign-up/index.html b/0.25.3/leapp-pro/getting-started/sign-up/index.html deleted file mode 100644 index 3bcd13c44..000000000 --- a/0.25.3/leapp-pro/getting-started/sign-up/index.html +++ /dev/null @@ -1 +0,0 @@ - Sign-up - Leapp - Docs

Sign-up

A Leapp Pro upgrade is required to enable new workspace features like Cloud access from multiple locations and Workspace locking.

Sign-up to Leapp Pro

To sign up for Leapp Pro you should upgrade your version of Leapp Community edition. Click on the Options button in the top-right area.

Settings button
Settings button

In the Options dialog, select the Plans tab and click on Upgrade to Pro button.

Plans tab
Plans tab

The upgrade window should appear. Enter your email (it will be the email address associated with your Leapp Pro account) and click on the Upgrade now button.

Upgrade window
Upgrade window

At this point a window will appear, so you can specify a payment method to complete the Leapp Pro upgrade. After the payment process you will receive a confirmation email containing the Complete the registration link.

Upgrade email
Upgrade email

Clicking the link in the confirmation email will open a web page that will allow you to enter your personal info and the master-password, essential to provide the security requirements of Leapp Pro.

Sign-up page
Sign-up page

After entering your personal info and the master-password click the Continue button. You can now finally sign in to Leapp Pro.

Troubles in signing up to Leapp Pro?

In case of any troubles signing up to Leapp Pro please contact us.

How to Sign-in

Take a look to this page to sign-in your Leapp Pro workspace.

\ No newline at end of file diff --git a/0.25.3/leapp-pro/security-and-password/index.html b/0.25.3/leapp-pro/security-and-password/index.html deleted file mode 100644 index a254d61b4..000000000 --- a/0.25.3/leapp-pro/security-and-password/index.html +++ /dev/null @@ -1 +0,0 @@ - Security and password - Leapp - Docs

Password issues

Can I recover my password?

Unfortunately, it is not possible to recover the master password. The master password is very important as it's the key point of our zero-knowledge encryption mechanism. If you forget it, you'll lose access to the previously encrypted Leapp Sessions and Integrations. That's why it is crucial that you keep your password safe; we suggest you to store it in a password manager like 1Password.

How is my data encrypted?

All information associated with your stored data is protected with end-to-end encryption. Leapp Sessions and Integrations are encrypted before being forwarded to the backend. Specifically, Leapp Pro uses AES 256-bit encryption as well as PBKDF-SHA512 to secure your data.

AES is a standard in cryptography and is used by the U.S. government and other government agencies around the world for protecting top-secret data. With proper implementation and a strong encryption key (your Master Password), AES is considered unbreakable.

PBKDF-SHA512 is used to derive the encryption key from your master password. Then this key is salted and hashed for authenticating with the Leapp Pro backend. The default iteration count used with PBKDF2 is 500,000 iterations on the client. Each Secret has its own generated symmetric key; this symmetric key is encrypted using the user’s public RSA key (this is also the foundation of the Secret sharing system). This encryption and decryption are done entirely on the Leapp Pro clients because your master password is never stored on or transmitted to Leapp Team backend.

It is important to highlight the fact that the backend does not act as a credentials broker, i.e. it has no visibility on the long-term/short-term credentials used by Leapp Pro Desktop App/CLI to access the cloud providers. In addition, the secrets retrieved from the backend, are an encrypted version of access configurations; access configurations DO NOT include temporary credentials. There is a single edge case: the IAM User. Indeed, the IAM User Session access configuration contains IAM User’s access keys, which are long-term credentials. Still, the Leapp Pro backend has no visibility on these long-term credentials, as they’re encrypted by the client before being forwarded to the Leapp Team backend.

Touch ID

When you unlock Leapp Pro, using a longer and more secure account password is easier than you might otherwise have chosen.

Your fingerprint is not stored in Leapp.

Leapp never scans or stores your fingerprint. Touch ID is provided by macOS, which only tells Leapp Pro if your fingerprint was recognized or not.

Learn more about Touch ID's advanced security technology.

\ No newline at end of file diff --git a/0.25.3/leapp-pro/synchronization/index.html b/0.25.3/leapp-pro/synchronization/index.html deleted file mode 100644 index fbe1b0356..000000000 --- a/0.25.3/leapp-pro/synchronization/index.html +++ /dev/null @@ -1 +0,0 @@ - Synchronization - Leapp - Docs

Synchronization

What's a Pro Workspace

A Pro Workspace is a new Workspace that is created upon first login with your registered Pro User. This workspace is synchronized with your Cloud account every time you create, edit, or delete an integration or a session; this way it is possible to use Leapp Pro on different devices, maintaining all your saved integrations and sessions.

How the Synchronization works

Synchronization works by encrypting all your sessions and integrations with your master password, created during your sign-up process. This way we maintain a 0-knowlegde approach on your data through all the lifecycle of your Pro workspace.

The encrypted data is then saved in the Cloud on your Leapp Pro personal space.

You, as a Leapp Pro user, can always keep an eye on the status of synchronization using the synchronization widget in the bottom-left area of Leapp.

Synchronization widget - synchronization active and done
Synchronization widget - synchronization active and done

When all the data is correctly synchronized you'll see the image above.

When Leapp Pro is synchronizing you'll see the icon and text changing to the one in the image below.

Synchronization widget - synchronization in progress
Synchronization widget - synchronization in progress

If you eventually lose connection or have a problem in synchronizing your data the widget will turn yellow as shown below.

Synchronization widget - synchronization failed
Synchronization widget - synchronization failed

You have the possibility to manually trigger another synchronization process and see if the problem is resolved.

Info

When Leapp Pro is restarted it will try to synchronize your data in the Cloud if you're logged in, so you can also close Leapp safely even if in synch failed state.

Do you have any trouble with Synchronization

In case of any troubles locking Leapp Pro workspace please contact us.

\ No newline at end of file diff --git a/0.25.3/plugins/plugins-development/index.html b/0.25.3/plugins/plugins-development/index.html index 24b463535..b5b8b98be 100644 --- a/0.25.3/plugins/plugins-development/index.html +++ b/0.25.3/plugins/plugins-development/index.html @@ -1,4 +1,4 @@ - Developer Reference - Leapp - Docs

Developer Reference

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

PluginEnvironment

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

log

  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description
message string the message to show
level LogLevel severity of the message
display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files

fetch

  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description
url string a valid HTTP URL to fetch from

openExternalUrl

  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description
url string a valid HTTP URL to open in the default browser

createSession

  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description
createSessionData SessionData the metadata used to create the Leapp Session

cloneSession

  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
session Session the Leapp Session that I want to clone

updateSession

  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
updateSessionData SessionData the metadata used to update the given Leapp Session
session Session the Leapp Session that I want to update

openTerminal

  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description
command string the command that I want to execute in the platform-specific terminal
env any optional key/value env variables object

getProfileIdByName

  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description
profileName string a valid named profile

getIdpUrlIdByUrl

  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description
url string the URL associated with the IdpUrl I want to retrieve

Example: display a toast message in Leapp

this.pluginEnvironment.log("Hello World", LogLevel.info, true);
+ Developer Reference - Leapp - Docs      

Developer Reference

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

PluginEnvironment

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

log

  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description
message string the message to show
level LogLevel severity of the message
display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files

fetch

  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description
url string a valid HTTP URL to fetch from

openExternalUrl

  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description
url string a valid HTTP URL to open in the default browser

createSession

  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description
createSessionData SessionData the metadata used to create the Leapp Session

cloneSession

  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
session Session the Leapp Session that I want to clone

updateSession

  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
updateSessionData SessionData the metadata used to update the given Leapp Session
session Session the Leapp Session that I want to update

openTerminal

  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description
command string the command that I want to execute in the platform-specific terminal
env any optional key/value env variables object

getProfileIdByName

  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description
profileName string a valid named profile

getIdpUrlIdByUrl

  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description
url string the URL associated with the IdpUrl I want to retrieve

Example: display a toast message in Leapp

this.pluginEnvironment.log("Hello World", LogLevel.info, true);
 

Example: fetch basic usage

const res = await this.pluginEnvironment.fetch(""); //Insert a custom URL
 const response = await res.json();
 

Example: open a URL in the browser

this.pluginEnvironment.openExternalUrl("https://leapp.cloud");
@@ -100,4 +100,4 @@
     this.pluginEnvironment.openExternalUrl(loginURL);
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/0.25.3/plugins/plugins-introduction/index.html b/0.25.3/plugins/plugins-introduction/index.html index 6f90f783f..583da7aa3 100644 --- a/0.25.3/plugins/plugins-introduction/index.html +++ b/0.25.3/plugins/plugins-introduction/index.html @@ -1,4 +1,4 @@ - Introduction to Plugins - Leapp - Docs

Introduction to Plugins

This section provides an overview of Leapp’s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

Add a Plugin

To add a plugin you can use one of the following methods:

Add from npm

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

Add manually

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

Disable a Plugin

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

Remove a Plugin

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

Run a Plugin

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

Plugin Menu

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

Create your Plugin

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             
+ Introduction to Plugins - Leapp - Docs      

Introduction to Plugins

This section provides an overview of Leapp’s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

Add a Plugin

To add a plugin you can use one of the following methods:

Add from npm

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

Add manually

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

Disable a Plugin

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

Remove a Plugin

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

Run a Plugin

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

Plugin Menu

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

Create your Plugin

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             
  ├── package.json      # Plugin metadata
  └── plugin.js         # A webpack bundle for the main logic
-

Create your Plugin

\ No newline at end of file +

Create your Plugin

\ No newline at end of file diff --git a/0.25.3/search/search_index.json b/0.25.3/search/search_index.json index 570a82e7f..31edc17af 100644 --- a/0.25.3/search/search_index.json +++ b/0.25.3/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Overview","text":""},{"location":"#overview","title":"Overview","text":""},{"location":"#welcome-to-leapp","title":"Welcome to Leapp","text":"

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

"},{"location":"#introducing-leapp-cli","title":"Introducing Leapp CLI","text":"

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

"},{"location":"configuration/","title":"Add your first configuration","text":"

Now it's time to add your very first configuration. Follow the link to your preferred supported method and start enjoying Leapp.

"},{"location":"configuration/#sessions","title":"Sessions","text":""},{"location":"configuration/#aws","title":"AWS","text":"

Select the configuration you need from the Access Method dropdown menu:

Leapp Iam User

Then follow the links below.

  • Configure an AWS IAM User
  • Configure an AWS IAM Role Federated
  • Configure an AWS IAM Role Chained
  • Configure LocalStack
"},{"location":"configuration/#integrations","title":"Integrations","text":""},{"location":"configuration/#aws-sso","title":"AWS SSO","text":"
  • Configure AWS SSO
"},{"location":"configuration/#azure-ad","title":"Azure AD","text":"
  • Configure an Azure Tenant
"},{"location":"edit-session/","title":"Editing a session","text":"

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can\u2019t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select \"edit session\". A new modal will appear, allowing the user to choose which parameters to change.

edit session

Below are the configuration options for every type of session:

"},{"location":"edit-session/#iam-user","title":"Iam User","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault
"},{"location":"edit-session/#iam-role-chained","title":"IAM Role Chained","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing \"Create Chained Session\"

"},{"location":"edit-session/#iam-role-federated","title":"IAM Role Federated","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

"},{"location":"edit-session/#how-we-handle-secrets-when-editing-a-session","title":"How we handle Secrets when Editing a Session","text":"

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

"},{"location":"integrations/","title":"Integrations","text":"

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

"},{"location":"integrations/#actions","title":"Actions","text":"

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description CREATE Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions. DELETE Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.) SYNC Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status. LOGOUT Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it."},{"location":"integrations/#supported-services","title":"Supported Services","text":"Service Supported AWS SSO Okta Coming Soon OneLogin Coming Soon AzureAD"},{"location":"sessions/","title":"Sessions","text":""},{"location":"sessions/#sessions","title":"Sessions","text":"

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

"},{"location":"sessions/#actions","title":"Actions","text":"Method Description START \u00a0Make the temporary credentials available to the provider chain STOP \u00a0Removes the temporary credentials from the provider chain ROTATE \u00a0Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

"},{"location":"workspaces/","title":"Workspaces","text":""},{"location":"workspaces/#workspaces","title":"Workspaces","text":"

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

"},{"location":"workspaces/#local","title":"Local","text":"

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

"},{"location":"workspaces/#remote","title":"Remote","text":"

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

"},{"location":"workspaces/#actions","title":"Actions","text":"

The actions below only applies to Remote workspaces.

Action Description Sign-in \u00a0Connect to a Remote workspace. This action will not switch your Local workspace Switch \u00a0Switch to the selected workspace by clicking on its name in the workspace menu Lock \u00a0Switch back to the Local workspace disabling all the Remote ones Sign-out \u00a0Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

"},{"location":"built-in-features/aws-ec2-connect/","title":"Configure AWS EC2 Connect","text":""},{"location":"built-in-features/aws-ec2-connect/#what-is-aws-ec2-connect","title":"What is AWS EC2 Connect","text":"

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

"},{"location":"built-in-features/aws-ec2-connect/#how-to-configure-aws-ec2-connect-in-leapp","title":"How To configure AWS EC2 Connect in Leapp","text":"

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.
"},{"location":"built-in-features/aws-ec2-connect/#video-tutorial","title":"Video tutorial","text":"

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

"},{"location":"built-in-features/aws-named-profiles/","title":"Configure Named Profiles","text":""},{"location":"built-in-features/aws-named-profiles/#what-is-a-named-profile","title":"What is a Named Profile","text":"

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

"},{"location":"built-in-features/aws-named-profiles/#how-to-configure-a-named-profile-in-leapp","title":"How to configure a Named Profile in Leapp","text":"

Named Profiles can be created in 3 ways:

Option PanelWhen creating a new SessionEdit Profile in Contextual Menu

Click on the gear icon and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the \"Change Profile\" option in the session list.

"},{"location":"built-in-features/aws-named-profiles/#named-profile-list","title":"Named Profile List","text":"

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

"},{"location":"built-in-features/general-options/","title":"General Options","text":"

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

"},{"location":"built-in-features/general-options/#default-regions","title":"Default Regions","text":"

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

"},{"location":"built-in-features/general-options/#terminal-selection","title":"Terminal Selection","text":"

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

"},{"location":"built-in-features/general-options/#color-theme","title":"Color Theme","text":"

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

"},{"location":"built-in-features/general-options/#default-webconsole-duration","title":"Default Webconsole Duration","text":"

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

"},{"location":"built-in-features/multi-console/","title":"Configure Multi Console","text":""},{"location":"built-in-features/multi-console/#what-is-multi-console","title":"What is Multi Console","text":"

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

Get it on Firefox \u21e9 Get it on Chrome \u21e9"},{"location":"built-in-features/multi-console/#list-of-supported-browsers","title":"List of Supported Browsers","text":"Browser Supported Firefox Chrome Edge Brave Safari"},{"location":"built-in-features/multi-console/#how-to-configure-multi-console-in-leapp","title":"How to Configure Multi Console in Leapp","text":""},{"location":"built-in-features/multi-console/#install-the-extension","title":"Install the Extension","text":""},{"location":"built-in-features/multi-console/#firefox","title":"Firefox","text":"

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox \u21e9

"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers","title":"Chrome, Edge and other Chromium based browsers","text":"

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others \u21e9

"},{"location":"built-in-features/multi-console/#uninstall-the-extension","title":"Uninstall the Extension","text":""},{"location":"built-in-features/multi-console/#firefox_1","title":"Firefox","text":"
  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove
"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers_1","title":"Chrome, Edge and other Chromium based browsers","text":"
  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select \"Cookies\". Then, remove all cookies by clicking \"Remove\" until the cookie list is empty and finally click on Done

"},{"location":"built-in-features/multi-console/#how-to-use-it","title":"How to use it","text":"

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).

By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

"},{"location":"built-in-features/opening-web-console/","title":"Configure Open Web Console","text":""},{"location":"built-in-features/opening-web-console/#what-is-open-web-console","title":"What is Open Web Console","text":"

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

"},{"location":"built-in-features/opening-web-console/#how-to-configure-open-web-console-in-leapp","title":"How to Configure Open Web Console in Leapp","text":"

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

"},{"location":"cli/","title":"Index","text":"

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli\n$ leapp COMMAND\nrunning command...\n$ leapp (--version)\n@noovolari/leapp-cli/0.1.65 darwin-x64 node-v21.6.2\n$ leapp --help [COMMAND]\nUSAGE\n  $ leapp COMMAND\n...\n
"},{"location":"cli/#command-topics","title":"Command Topics","text":"
  • leapp help - Display help for leapp.
  • leapp idp-url - SAML 2.0 Identity providers URL management
  • leapp integration - Leapp Integrations management
  • leapp profile - Leapp AWS Multi-profile management
  • leapp region - Leapp regions management
  • leapp session - Sessions management
  • leapp set-workspace - Set the current Leapp workspace
  • leapp team - Login to your Team account
  • leapp version - Displays the Cli and Core versions
  • leapp workspace - Show the current workspace
"},{"location":"cli/scopes/help/","title":"Help","text":""},{"location":"cli/scopes/help/#leapp-help","title":"leapp help","text":"

Display help for leapp.

  • leapp help [COMMANDS]
"},{"location":"cli/scopes/help/#leapp-help-commands","title":"leapp help [COMMANDS]","text":"

Display help for leapp.

USAGE\n  $ leapp help [COMMANDS] [-n]\n\nARGUMENTS\n  COMMANDS  Command to show help for.\n\nFLAGS\n  -n, --nested-commands  Include all nested commands in the output.\n\nDESCRIPTION\n  Display help for leapp.\n

See code: @oclif/plugin-help

"},{"location":"cli/scopes/idp-url/","title":"Idp Url","text":""},{"location":"cli/scopes/idp-url/#leapp-idp-url","title":"leapp idp-url","text":"

SAML 2.0 Identity providers URL management

  • leapp idp-url create
  • leapp idp-url delete
  • leapp idp-url edit
  • leapp idp-url list
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-create","title":"leapp idp-url create","text":"

Create a new identity provider URL

USAGE\n  $ leapp idp-url create [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>  the idp url address we want to create\n\nDESCRIPTION\n  Create a new identity provider URL\n\nEXAMPLES\n  $leapp idp-url create\n\n  $leapp idp-url create --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-delete","title":"leapp idp-url delete","text":"

Delete an identity provider URL

USAGE\n  $ leapp idp-url delete [--idpUrlId <value>] [-f]\n\nFLAGS\n  -f, --force         force a command without asking for confirmation (-f, --force)\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Delete an identity provider URL\n\nEXAMPLES\n  $leapp idp-url delete\n\n  $leapp idp-url delete --idpUrlId ID\n\n  $leapp idp-url delete --idpUrlId ID [--force, -f]\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-edit","title":"leapp idp-url edit","text":"

Edit an identity provider URL

USAGE\n  $ leapp idp-url edit [--idpUrlId <value>] [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>    the idp url address we want to create\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Edit an identity provider URL\n\nEXAMPLES\n  $leapp idp-url edit\n\n  $leapp idp-url edit --idpUrlId ID --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-list","title":"leapp idp-url list","text":"

Show identity providers list

USAGE\n  $ leapp idp-url list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show identity providers list\n\nEXAMPLES\n  $leapp idp-url list\n
"},{"location":"cli/scopes/integration/","title":"Integration","text":""},{"location":"cli/scopes/integration/#leapp-integration","title":"leapp integration","text":"

Leapp Integrations management

  • leapp integration create
  • leapp integration delete
  • leapp integration list
  • leapp integration login
  • leapp integration logout
  • leapp integration sync
"},{"location":"cli/scopes/integration/#leapp-integration-create","title":"leapp integration create","text":"

Create a new integration

USAGE\n  $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]\n    [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]\n\nFLAGS\n  --integrationAlias=<value>      alias that identifies an integration\n  --integrationLocation=<value>   Location of an Azure Integration\n  --integrationPortalUrl=<value>  url that identifies the integration portal where you authenticate\n  --integrationRegion=<value>     an AWS valid region code for the integration\n  --integrationTenantId=<value>   Tenant ID of an Azure Integration\n  --integrationType=<option>      Identify the type of your integration. Valid types are [AWS-SSO, AZURE]\n                                  <options: AWS-SSO|AZURE>\n\nDESCRIPTION\n  Create a new integration\n\nEXAMPLES\n  $leapp integration create\n\n  $leapp integration create --integrationType AWS-SSO --integrationAlias ALIAS --integrationPortalUrl URL --integrationRegion REGION\n\n  $leapp integration create --integrationType AZURE --integrationAlias ALIAS --integrationTenantId TENANT --integrationLocation LOCATION\n
"},{"location":"cli/scopes/integration/#leapp-integration-delete","title":"leapp integration delete","text":"

Delete an integration

USAGE\n  $ leapp integration delete [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Delete an integration\n\nEXAMPLES\n  $leapp integration delete\n\n  $leapp integration delete --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-list","title":"leapp integration list","text":"

Show integrations list

USAGE\n  $ leapp integration list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show integrations list\n\nEXAMPLES\n  $leapp integration list\n
"},{"location":"cli/scopes/integration/#leapp-integration-login","title":"leapp integration login","text":"

Login to synchronize integration sessions

USAGE\n  $ leapp integration login [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Login to synchronize integration sessions\n\nEXAMPLES\n  $leapp integration login\n\n  $leapp integration login --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-logout","title":"leapp integration logout","text":"

Logout from an integration

USAGE\n  $ leapp integration logout [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Logout from an integration\n\nEXAMPLES\n  $leapp integration logout\n\n  $leapp integration logout --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-sync","title":"leapp integration sync","text":"

Synchronize integration sessions

USAGE\n  $ leapp integration sync [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Synchronize integration sessions\n\nEXAMPLES\n  $leapp integration sync\n\n  $leapp integration sync --integrationId ID\n
"},{"location":"cli/scopes/profile/","title":"Profile","text":""},{"location":"cli/scopes/profile/#leapp-profile","title":"leapp profile","text":"

Leapp AWS Multi-profile management

  • leapp profile create
  • leapp profile delete
  • leapp profile edit
  • leapp profile list
"},{"location":"cli/scopes/profile/#leapp-profile-create","title":"leapp profile create","text":"

Create a new AWS named profile

USAGE\n  $ leapp profile create [--profileName <value>]\n\nFLAGS\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Create a new AWS named profile\n\nEXAMPLES\n  $leapp profile create\n\n  $leapp profile create --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-delete","title":"leapp profile delete","text":"

Delete an AWS named profile

USAGE\n  $ leapp profile delete [--profileId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --profileId=<value>  an AWS named profile ID in Leapp\n\nDESCRIPTION\n  Delete an AWS named profile\n\nEXAMPLES\n  $leapp profile delete\n\n  $leapp profile delete --profileId PROFILEID\n\n  $leapp profile delete --profileId PROFILEID [--force, -f]\n
"},{"location":"cli/scopes/profile/#leapp-profile-edit","title":"leapp profile edit","text":"

Rename an AWS named profile

USAGE\n  $ leapp profile edit [--profileId <value>] [--profileName <value>]\n\nFLAGS\n  --profileId=<value>    an AWS named profile ID in Leapp\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Rename an AWS named profile\n\nEXAMPLES\n  $leapp profile edit\n\n  $leapp profile edit --profileId ID --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-list","title":"leapp profile list","text":"

Show profile list

USAGE\n  $ leapp profile list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show profile list\n\nEXAMPLES\n  $leapp profile list\n
"},{"location":"cli/scopes/region/","title":"Region","text":""},{"location":"cli/scopes/region/#leapp-region","title":"leapp region","text":"

Leapp regions management

  • leapp region get-default
  • leapp region set-default
"},{"location":"cli/scopes/region/#leapp-region-get-default","title":"leapp region get-default","text":"

Displays the default region

USAGE\n  $ leapp region get-default\n\nDESCRIPTION\n  Displays the default region\n\nEXAMPLES\n  $leapp region get-default\n
"},{"location":"cli/scopes/region/#leapp-region-set-default","title":"leapp region set-default","text":"

Change the default region

USAGE\n  $ leapp region set-default [--region <value>]\n\nFLAGS\n  --region=<value>  Session Region for AWS sessions in Leapp\n\nDESCRIPTION\n  Change the default region\n\nEXAMPLES\n  $leapp region set-default\n\n  $leapp region set-default --region AWSREGION\n
"},{"location":"cli/scopes/session/","title":"Session","text":""},{"location":"cli/scopes/session/#leapp-session","title":"leapp session","text":"

Sessions management

  • leapp session add
  • leapp session change-profile
  • leapp session change-region
  • leapp session current
  • leapp session delete
  • leapp session generate SESSIONID
  • leapp session get-id
  • leapp session list
  • leapp session open-web-console
  • leapp session run-aws-credential-plugin
  • leapp session start [SESSIONNAME]
  • leapp session start-ssm-session
  • leapp session stop [SESSIONNAME]
"},{"location":"cli/scopes/session/#leapp-session-add","title":"leapp session add","text":"

Add a new session

USAGE\n  $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]\n    [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]\n    [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType\n    awsIamRoleFederated|awsIamUser|awsIamRoleChained]\n\nFLAGS\n  --accessKey=<value>        AWS Access Key ID of the IAM User\n  --idpArn=<value>           AWS IAM Federated Role IdP Arn value, obtain it from your AWS Account\n  --idpUrl=<value>           the idp url address we want to create\n  --mfaDevice=<value>        MFA Device Arn retrieved from your AWS Account\n  --parentSessionId=<value>  For AWS IAM Role Chained is the session Id of the session that will assume the chained\n                             role. Retrieve it using $leapp session list -x\n  --profileId=<value>        an AWS named profile ID in Leapp\n  --providerType=<option>    Identify the provider for your sessions. Valid types are [aws]\n                             <options: aws>\n  --region=<value>           Session Region for AWS sessions in Leapp\n  --roleArn=<value>          AWS IAM Federated Role Arn value, obtain it from your AWS Account\n  --roleSessionName=<value>  Optional Alias for the Assumed Role Session name\n  --secretKey=<value>        AWS Secret Access Key of the IAM User\n  --sessionName=<value>      Session Alias to identify the session in Leapp\n  --sessionType=<option>     Identify the AWS session type. Valid types are [awsIamRoleFederated, awsIamUser,\n                             awsIamRoleChained]\n                             <options: awsIamRoleFederated|awsIamUser|awsIamRoleChained>\n\nDESCRIPTION\n  Add a new session\n\nEXAMPLES\n  $leapp session add\n\n  $leapp session add --providerType [aws] --sessionType [awsIamRoleFederated, awsIamRoleChained, awsIamUser] --region [AWSREGION] --sessionName NAME ...[combination of flags relative to the session]\n\n  $leapp session add --providerType aws --sessionType awsIamRoleFederated --sessionName NAME --region AWSREGION --idpArn IDPARN --idpUrl IDPURL --profileId PROFILEID --roleArn ROLEARN\n\n  $leapp session add --providerType aws --sessionType awsIamRoleChained --sessionName NAME --region AWSREGION --profileId PROFILEID --roleArn ROLEARN --parentSessionId ID (--roleSessionName ROLESESSIONNAME)\n\n  $leapp session add --providerType aws --sessionType awsIamUser --sessionName NAME --region AWSREGION --profileId PROFILEID --accessKey ACCESSKEY --secretKey SECRETKEY (--mfaDevice MFADEVICEARN)\n
"},{"location":"cli/scopes/session/#leapp-session-change-profile","title":"leapp session change-profile","text":"

Change a session named-profile

USAGE\n  $ leapp session change-profile [--sessionId <value>] [--profileId <value>]\n\nFLAGS\n  --profileId=<value>  an AWS named profile ID in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session named-profile\n\nEXAMPLES\n  $leapp session change-profile\n\n  $leapp session change-profile --profileId PROFILEID --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-change-region","title":"leapp session change-region","text":"

Change a session region

USAGE\n  $ leapp session change-region [--sessionId <value>] [--region <value>]\n\nFLAGS\n  --region=<value>     Session Region for AWS sessions in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session region\n\nEXAMPLES\n  $leapp session change-region\n\n  $leapp session change-region --sessionId SESSIONID --region REGION\n
"},{"location":"cli/scopes/session/#leapp-session-current","title":"leapp session current","text":"

Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile default)

USAGE\n  $ leapp session current [-i] [-p <value>] [-r aws|azure] [-f <value>]\n\nFLAGS\n  -f, --format=<value>     allows formatting data to show\n                           - aws -> id alias, accountNumber, roleArn\n                           - azure -> id tenantId, subscriptionId\n  -i, --inline\n  -p, --profile=<value>    [default: default] aws named profile of which gets info\n  -r, --provider=<option>  filters sessions by the cloud provider service\n                           <options: aws|azure>\n\nDESCRIPTION\n  Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile\n  default)\n\nEXAMPLES\n  $leapp session current --format \"alias accountNumber\" --inline --provider aws\n
"},{"location":"cli/scopes/session/#leapp-session-delete","title":"leapp session delete","text":"

Delete a session

USAGE\n  $ leapp session delete [--sessionId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Delete a session\n\nEXAMPLES\n  $leapp session delete\n\n  $leapp session delete --sessionId SESSIONID\n\n  $leapp session delete --sessionId SESSIONID [--force, -f]\n
"},{"location":"cli/scopes/session/#leapp-session-generate-sessionid","title":"leapp session generate SESSIONID","text":"

Generate STS temporary credentials for the given AWS session id

USAGE\n  $ leapp session generate SESSIONID\n\nARGUMENTS\n  SESSIONID  id of the session\n\nDESCRIPTION\n  Generate STS temporary credentials for the given AWS session id\n\nEXAMPLES\n  $leapp session generate 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d\n
"},{"location":"cli/scopes/session/#leapp-session-get-id","title":"leapp session get-id","text":"

Get session id

USAGE\n  $ leapp session get-id\n\nDESCRIPTION\n  Get session id\n\nEXAMPLES\n  $leapp session get-id\n
"},{"location":"cli/scopes/session/#leapp-session-list","title":"leapp session list","text":"

Show sessions list with all properties; filter query is case sensitive

USAGE\n  $ leapp session list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show sessions list with all properties; filter query is case sensitive\n\nEXAMPLES\n  $leapp session list\n\n  $leapp session list --filter=\"ID=Foo\" -x\n\n  $leapp session list --filter=\"Session Name=Foo\"\n\n  $leapp session list --filter=\"Type=Foo\"\n\n  $leapp session list --filter=\"Named Profile=Foo\"\n\n  $leapp session list --filter=\"Region/Location=Foo\"\n\n  $leapp session list --filter=\"Status=Foo\"\n
"},{"location":"cli/scopes/session/#leapp-session-open-web-console","title":"leapp session open-web-console","text":"

Open an AWS Web Console

USAGE\n  $ leapp session open-web-console [--sessionId <value>] [-p]\n\nFLAGS\n  -p, --print          Print an AWS Web Console login URL in the terminal instead of opening the web browser\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Open an AWS Web Console\n\nEXAMPLES\n  $leapp session open-web-console\n\n  $leapp session open-web-console --sessionId SESSIONID [--print, -p]\n
"},{"location":"cli/scopes/session/#leapp-session-run-aws-credential-plugin","title":"leapp session run-aws-credential-plugin","text":"

Run a Leapp Plugin

USAGE\n  $ leapp session run-aws-credential-plugin [--sessionId <value>] [--pluginName <value>]\n\nFLAGS\n  --pluginName=<value>  Unique name of a Leapp Plugin\n  --sessionId=<value>   Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Run a Leapp Plugin\n\nEXAMPLES\n  $leapp session run-plugin\n\n  $leapp session run-plugin --sessionName SESSIONAME --pluginName PLUGINNAME\n
"},{"location":"cli/scopes/session/#leapp-session-start-sessionname","title":"leapp session start [SESSIONNAME]","text":"

Start a session

USAGE\n  $ leapp session start [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Start a session\n\nEXAMPLES\n  $leapp session start\n\n  $leapp session start SESSIONNAME\n\n  $leapp session start SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session start SESSIONNAME --noInteractive\n\n  $leapp session start --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-start-ssm-session","title":"leapp session start-ssm-session","text":"

Start an AWS SSM session

USAGE\n  $ leapp session start-ssm-session [--sessionId <value>] [--region <value>] [--ssmInstanceId <value>]\n\nFLAGS\n  --region=<value>         Session Region for AWS sessions in Leapp\n  --sessionId=<value>      Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --ssmInstanceId=<value>  Instance ID for EC2 instance we want to access with SSM\n\nDESCRIPTION\n  Start an AWS SSM session\n\nEXAMPLES\n  $leapp session start-ssm-session\n\n  $leapp session start-ssm-session --sessionId SESSIONID --region AWSREGION --ssmInstanceId EC2INSTANCEID\n
"},{"location":"cli/scopes/session/#leapp-session-stop-sessionname","title":"leapp session stop [SESSIONNAME]","text":"

Stop a session

USAGE\n  $ leapp session stop [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Stop a session\n\nEXAMPLES\n  $leapp session stop\n\n  $leapp session stop SESSIONNAME\n\n  $leapp session stop SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session stop SESSIONNAME --noInteractive\n\n  $leapp session stop --sessionId SESSIONID\n
"},{"location":"cli/scopes/set-workspace/","title":"Set Workspace","text":""},{"location":"cli/scopes/set-workspace/#leapp-set-workspace","title":"leapp set-workspace","text":"

Set the current Leapp workspace

  • leapp set-workspace [WORKSPACENAME]
"},{"location":"cli/scopes/set-workspace/#leapp-set-workspace-workspacename","title":"leapp set-workspace [WORKSPACENAME]","text":"

Set the current Leapp workspace

USAGE\n  $ leapp set-workspace [WORKSPACENAME]\n\nARGUMENTS\n  WORKSPACENAME  name of the Leapp Team remote workspace or local\n\nDESCRIPTION\n  Set the current Leapp workspace\n\nEXAMPLES\n  $leapp team set-workspace\n\n  $leapp team set-workspace local\n\n  $leapp team set-workspace WORKSPACE-NAME\n

See code: dist/commands/set-workspace.ts

"},{"location":"cli/scopes/team/","title":"Team","text":""},{"location":"cli/scopes/team/#leapp-team","title":"leapp team","text":"

Login to your Team account

  • leapp team login
  • leapp team logout
  • leapp team status
"},{"location":"cli/scopes/team/#leapp-team-login","title":"leapp team login","text":"

Login to your Team account

USAGE\n  $ leapp team login\n\nDESCRIPTION\n  Login to your Team account\n\nEXAMPLES\n  $leapp team login\n
"},{"location":"cli/scopes/team/#leapp-team-logout","title":"leapp team logout","text":"

Logout from your Team account

USAGE\n  $ leapp team logout\n\nDESCRIPTION\n  Logout from your Team account\n\nEXAMPLES\n  $leapp team logout\n
"},{"location":"cli/scopes/team/#leapp-team-status","title":"leapp team status","text":"

Get the team login status

USAGE\n  $ leapp team status\n\nDESCRIPTION\n  Get the team login status\n\nEXAMPLES\n  $leapp team status\n
"},{"location":"cli/scopes/version/","title":"Version","text":""},{"location":"cli/scopes/version/#leapp-version","title":"leapp version","text":"

Displays the Cli and Core versions

  • leapp version
"},{"location":"cli/scopes/version/#leapp-version_1","title":"leapp version","text":"

Displays the Cli and Core versions

USAGE\n  $ leapp version\n\nDESCRIPTION\n  Displays the Cli and Core versions\n\nEXAMPLES\n  $leapp version\n

See code: dist/commands/version.ts

"},{"location":"cli/scopes/workspace/","title":"Workspace","text":""},{"location":"cli/scopes/workspace/#leapp-workspace","title":"leapp workspace","text":"

Show the current workspace

  • leapp workspace
"},{"location":"cli/scopes/workspace/#leapp-workspace_1","title":"leapp workspace","text":"

Show the current workspace

USAGE\n  $ leapp workspace\n\nDESCRIPTION\n  Show the current workspace\n\nEXAMPLES\n  $leapp workspace\n

See code: dist/commands/workspace.ts

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/","title":"Configure an AWS Identity Center (ex AWS Single Sign-On) integration","text":""},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#what-is-aws-identity-center-ex-aws-single-sign-on","title":"What is AWS Identity Center (ex AWS Single Sign-On)","text":"

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#how-to-configure-an-aws-identity-center-ex-aws-single-sign-on-integration-in-leapp","title":"How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as AWS Single Sign-on AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start. REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part."},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-integration/configure-azure-integration/","title":"Configure an Azure integration","text":""},{"location":"configuring-integration/configure-azure-integration/#what-is-an-azure-integration","title":"What is an Azure integration","text":"

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

"},{"location":"configuring-integration/configure-azure-integration/#how-to-configure-an-azure-integration-in-leapp","title":"How to configure an Azure integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-azure-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as Azure ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database. LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options."},{"location":"configuring-integration/configure-azure-integration/#video-tutorial","title":"Video tutorial","text":"

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

"},{"location":"configuring-session/configure-aws-iam-role-chained/","title":"Configure AWS IAM Role Chained","text":""},{"location":"configuring-session/configure-aws-iam-role-chained/#what-is-an-aws-iam-role-chained-session","title":"What is an AWS IAM Role Chained session","text":"

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

"},{"location":"configuring-session/configure-aws-iam-role-chained/#how-to-configure-an-aws-iam-role-chained-in-leapp","title":"How to configure an AWS IAM Role Chained in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-chained/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role. ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity. ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp."},{"location":"configuring-session/configure-aws-iam-role-chained/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/","title":"Configure AWS IAM Role Federated","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/#what-is-an-aws-iam-role-federated-session","title":"What is an AWS IAM Role Federated session","text":"

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#supported-saml-identity-providers","title":"Supported SAML Identity Providers","text":"Identity Provider AWS Azure GSUITE OKTA ONELOGIN AZURE AD AUTH0 KEYCLOAK JUMPCLOUD

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

"},{"location":"configuring-session/configure-aws-iam-role-federated/#how-to-configure-an-aws-iam-role-federated-in-leapp","title":"How to configure an AWS IAM Role Federated in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider. AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role."},{"location":"configuring-session/configure-aws-iam-role-federated/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-user/","title":"Configure AWS IAM User","text":""},{"location":"configuring-session/configure-aws-iam-user/#what-is-an-aws-iam-user-session","title":"What is an AWS IAM User session","text":"

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

"},{"location":"configuring-session/configure-aws-iam-user/#how-to-configure-an-aws-iam-user-in-leapp","title":"How to configure an AWS IAM User in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-user/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. MFA DEVICE Your MFA device ID to set up multi-factor authentication. ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. Add AWS IAM User Screen"},{"location":"configuring-session/configure-aws-iam-user/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-localstack/","title":"Configure LocalStack","text":""},{"location":"configuring-session/configure-localstack/#what-is-a-localstack-session","title":"What is a LocalStack session","text":"

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

"},{"location":"configuring-session/configure-localstack/#how-to-configure-a-localstack-session-in-leapp","title":"How to configure a LocalStack session in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

"},{"location":"contributing/get-involved/","title":"Get involved","text":""},{"location":"contributing/get-involved/#get-involved","title":"Get involved","text":"

Contributions and questions are not just welcome, they\u2019re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you\u2019re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you.

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

"},{"location":"installation/install-leapp/","title":"Install Leapp","text":""},{"location":"installation/install-leapp/#install-leapp-app","title":"Install Leapp App","text":""},{"location":"installation/install-leapp/#macos-windows-and-linux","title":"MacOS, Windows, and Linux","text":"

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp \u21e9

Unzip the package and double-click the executable to install.

"},{"location":"installation/install-leapp/#macos-homebrew","title":"macOS (Homebrew)","text":"

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp\n

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

"},{"location":"installation/install-leapp/#install-leapp-cli","title":"Install Leapp CLI","text":"

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli\n

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli\n
"},{"location":"installation/install-leapp/#install-leapp-cli-on-macos-with-arm64-chip-m1-m2","title":"Install Leapp CLI on macOS with ARM64 chip (M1, M2)","text":"

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64\n

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

"},{"location":"installation/requirements/","title":"Requirements","text":""},{"location":"installation/requirements/#requirements","title":"Requirements","text":""},{"location":"installation/requirements/#macos-and-windows","title":"MacOS and Windows","text":"

There are no requirements for macOS and Windows users.

"},{"location":"installation/requirements/#linux-systems","title":"Linux systems","text":"

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

Arch LinuxDebian/UbuntuRed Hat-based
sudo pacman -S gnome-keyring\nsudo pacman -S libsecret\n
sudo apt-get install gnome-keyring\nsudo apt-get install libsecret-1-dev\n
sudo yum install gnome-keyring\nsudo yum install libsecret-devel\n
"},{"location":"installation/requirements/#logging-into-ec2-instances-via-aws-ssm-with-leapp","title":"Logging into EC2 Instances via AWS SSM with Leapp","text":"

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>\n

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/\n

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html\n
"},{"location":"installation/update-leapp/","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#update-leapp","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#desktop-app","title":"Desktop App","text":"

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Remind me laterDownload updateClick on X

Leapp will close the modal and notify the user that a new update is available by adding a notification dot to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

"},{"location":"installation/update-leapp/#macos-homebrew-linux-linuxbrew-and-windows-via-wsl","title":"macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)","text":"

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

"},{"location":"installation/update-leapp/#cli","title":"CLI","text":"

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npmHomebrew (macOS)
npm update -g @noovolari/leapp-cli\n
brew upgrade Noovolari/brew/leapp-cli\n
"},{"location":"leapp-pro/export-pro-workspace/","title":"Export PRO Workspace","text":""},{"location":"leapp-pro/export-pro-workspace/#how-to-export-your-pro-workspace","title":"How to export your Pro Workspace","text":"
  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:\ncp Leapp-lock.json Leapp-lock.json.bkp\n
  2. log into you Pro Workspace using the Desktop App;

  3. from the Leapp Options \"General\" tab, click the button next to the \"Export Pro/Team workspace\" label;

  4. close the Leapp Options dialog;

  5. close Leapp (on macOS \u2318+Q);
  6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
  7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
    rm Leapp-lock.json\nmv Leapp-lock.json.exported Leapp-lock.json\n
  8. re-open Leapp;
  9. switch to the Local Workspace;
  10. you should now see your Pro Workspace migrated into the Local one.
"},{"location":"leapp-pro/security-and-password/","title":"Security and password","text":""},{"location":"leapp-pro/security-and-password/#password-issues","title":"Password issues","text":""},{"location":"leapp-pro/security-and-password/#can-i-recover-my-password","title":"Can I recover my password?","text":"

Unfortunately, it is not possible to recover the master password. The master password is very important as it's the key point of our zero-knowledge encryption mechanism. If you forget it, you'll lose access to the previously encrypted Leapp Sessions and Integrations. That's why it is crucial that you keep your password safe; we suggest you to store it in a password manager like 1Password.

"},{"location":"leapp-pro/security-and-password/#how-is-my-data-encrypted","title":"How is my data encrypted?","text":"

All information associated with your stored data is protected with end-to-end encryption. Leapp Sessions and Integrations are encrypted before being forwarded to the backend. Specifically, Leapp Pro uses AES 256-bit encryption as well as PBKDF-SHA512 to secure your data.

AES is a standard in cryptography and is used by the U.S. government and other government agencies around the world for protecting top-secret data. With proper implementation and a strong encryption key (your Master Password), AES is considered unbreakable.

PBKDF-SHA512 is used to derive the encryption key from your master password. Then this key is salted and hashed for authenticating with the Leapp Pro backend. The default iteration count used with PBKDF2 is 500,000 iterations on the client. Each Secret has its own generated symmetric key; this symmetric key is encrypted using the user\u2019s public RSA key (this is also the foundation of the Secret sharing system). This encryption and decryption are done entirely on the Leapp Pro clients because your master password is never stored on or transmitted to Leapp Team backend.

It is important to highlight the fact that the backend does not act as a credentials broker, i.e. it has no visibility on the long-term/short-term credentials used by Leapp Pro Desktop App/CLI to access the cloud providers. In addition, the secrets retrieved from the backend, are an encrypted version of access configurations; access configurations DO NOT include temporary credentials. There is a single edge case: the IAM User. Indeed, the IAM User Session access configuration contains IAM User\u2019s access keys, which are long-term credentials. Still, the Leapp Pro backend has no visibility on these long-term credentials, as they\u2019re encrypted by the client before being forwarded to the Leapp Team backend.

"},{"location":"leapp-pro/security-and-password/#touch-id","title":"Touch ID","text":"

When you unlock Leapp Pro, using a longer and more secure account password is easier than you might otherwise have chosen.

"},{"location":"leapp-pro/security-and-password/#your-fingerprint-is-not-stored-in-leapp","title":"Your fingerprint is not stored in Leapp.","text":"

Leapp never scans or stores your fingerprint. Touch ID is provided by macOS, which only tells Leapp Pro if your fingerprint was recognized or not.

Learn more about Touch ID's advanced security technology.

"},{"location":"leapp-pro/synchronization/","title":"Synchronization","text":""},{"location":"leapp-pro/synchronization/#whats-a-pro-workspace","title":"What's a Pro Workspace","text":"

A Pro Workspace is a new Workspace that is created upon first login with your registered Pro User. This workspace is synchronized with your Cloud account every time you create, edit, or delete an integration or a session; this way it is possible to use Leapp Pro on different devices, maintaining all your saved integrations and sessions.

"},{"location":"leapp-pro/synchronization/#how-the-synchronization-works","title":"How the Synchronization works","text":"

Synchronization works by encrypting all your sessions and integrations with your master password, created during your sign-up process. This way we maintain a 0-knowlegde approach on your data through all the lifecycle of your Pro workspace.

The encrypted data is then saved in the Cloud on your Leapp Pro personal space.

You, as a Leapp Pro user, can always keep an eye on the status of synchronization using the synchronization widget in the bottom-left area of Leapp.

Synchronization widget - synchronization active and done

When all the data is correctly synchronized you'll see the image above.

When Leapp Pro is synchronizing you'll see the icon and text changing to the one in the image below.

Synchronization widget - synchronization in progress

If you eventually lose connection or have a problem in synchronizing your data the widget will turn yellow as shown below.

Synchronization widget - synchronization failed

You have the possibility to manually trigger another synchronization process and see if the problem is resolved.

Info

When Leapp Pro is restarted it will try to synchronize your data in the Cloud if you're logged in, so you can also close Leapp safely even if in synch failed state.

"},{"location":"leapp-pro/synchronization/#do-you-have-any-trouble-with-synchronization","title":"Do you have any trouble with Synchronization","text":"

In case of any troubles locking Leapp Pro workspace please contact us.

"},{"location":"leapp-pro/getting-started/","title":"Getting Started","text":""},{"location":"leapp-pro/getting-started/#why-leapp-pro","title":"Why Leapp Pro?","text":"

Leapp Pro enable Users to protect their Cloud access with Username and password.

With Leapp Pro you can back up and synchronize your Leapp workspace and access to any device you want without losing your access configurations.

"},{"location":"leapp-pro/getting-started/#getting-started-guide","title":"Getting started guide","text":"
  • Sign up to Leapp Pro
  • Sign in to Leapp Pro
  • Lock your Leapp Pro Workspace
"},{"location":"leapp-pro/getting-started/#security-and-syncronization","title":"Security and syncronization","text":"

Once you updgrade your Plan to Leapp Pro, your local Workspace will be moved to the Pro Workspace. All the data inside your workspace are secured with end-to-end encryption through your Master password.

"},{"location":"leapp-pro/getting-started/lock/","title":"Lock your Workspace","text":"

Leapp Pro allows the user to temporary lock the workspace, making it accessible only by typing again your master-password. This feature provides a further security level on top of the standard Leapp Community edition.

"},{"location":"leapp-pro/getting-started/lock/#how-to-lock-the-leapp-pro-workspace","title":"How to lock the Leapp Pro workspace","text":"

To lock your Leapp Pro workspace you should click on the Workspace button located in the top-left area and select the Lock option.

Workspace button Lock option

The Leapp Pro lock screen should appear, prompting for your master-password.

Leapp Pro lock screen"},{"location":"leapp-pro/getting-started/lock/#touch-id","title":"Touch ID","text":"

You can also use your fingerprint to unlock Leapp if your PC is Touch ID compatible. After Logging to your Pro workspace for the first time, Leapp will associate your workspace with your system Touch ID. After that the option will be available and can also be tweaked in the general tab of the option menu.

"},{"location":"leapp-pro/getting-started/lock/#troubles-in-locking-your-workspace","title":"Troubles in locking your Workspace","text":"

In case of any troubles locking Leapp Pro workspace please contact us.

"},{"location":"leapp-pro/getting-started/sign-in/","title":"Sign-in","text":"

With Leapp Pro you can always sign-in from any location, gaining instant access to your personal workspace.

"},{"location":"leapp-pro/getting-started/sign-in/#sign-in-to-leapp-pro","title":"Sign-in to Leapp Pro","text":"

After upgrading Leapp Community edition, you can sign-in at any time, just clicking on the Workspace button located in the top-left area and selecting the Sign-in Workspace option.

Workspace button Sign-in Workspace option

The Sign-in Workspace dialog will appear. Enter your Email address, master-password and click on the Add Workspace button.

Sign-in dialog

If the information entered is correct, your Leapp Pro workspace will be displayed and you can immediately use it to manage your cloud credentials.

Leapp Pro Workspace

To avoid unwanted access, you can lock your Leapp Pro workspace at any time.

"},{"location":"leapp-pro/getting-started/sign-in/#troubles-in-signing-in-to-leapp-pro","title":"Troubles in signing in to Leapp Pro?","text":"

In case of any troubles signing in to Leapp Pro please contact us.

"},{"location":"leapp-pro/getting-started/sign-up/","title":"Sign-up","text":"

A Leapp Pro upgrade is required to enable new workspace features like Cloud access from multiple locations and Workspace locking.

"},{"location":"leapp-pro/getting-started/sign-up/#sign-up-to-leapp-pro","title":"Sign-up to Leapp Pro","text":"

To sign up for Leapp Pro you should upgrade your version of Leapp Community edition. Click on the Options button in the top-right area.

Settings button

In the Options dialog, select the Plans tab and click on Upgrade to Pro button.

Plans tab

The upgrade window should appear. Enter your email (it will be the email address associated with your Leapp Pro account) and click on the Upgrade now button.

Upgrade window

At this point a window will appear, so you can specify a payment method to complete the Leapp Pro upgrade. After the payment process you will receive a confirmation email containing the Complete the registration link.

Upgrade email

Clicking the link in the confirmation email will open a web page that will allow you to enter your personal info and the master-password, essential to provide the security requirements of Leapp Pro.

Sign-up page

After entering your personal info and the master-password click the Continue button. You can now finally sign in to Leapp Pro.

"},{"location":"leapp-pro/getting-started/sign-up/#troubles-in-signing-up-to-leapp-pro","title":"Troubles in signing up to Leapp Pro?","text":"

In case of any troubles signing up to Leapp Pro please contact us.

"},{"location":"leapp-pro/getting-started/sign-up/#how-to-sign-in","title":"How to Sign-in","text":"

Take a look to this page to sign-in your Leapp Pro workspace.

"},{"location":"plugins/plugins-development/","title":"Developer Reference","text":"

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

"},{"location":"plugins/plugins-development/#pluginenvironment","title":"PluginEnvironment","text":"

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

"},{"location":"plugins/plugins-development/#log","title":"log","text":"
  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description message string the message to show level LogLevel severity of the message display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files"},{"location":"plugins/plugins-development/#fetch","title":"fetch","text":"
  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description url string a valid HTTP URL to fetch from"},{"location":"plugins/plugins-development/#openexternalurl","title":"openExternalUrl","text":"
  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description url string a valid HTTP URL to open in the default browser"},{"location":"plugins/plugins-development/#createsession","title":"createSession","text":"
  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description createSessionData SessionData the metadata used to create the Leapp Session"},{"location":"plugins/plugins-development/#clonesession","title":"cloneSession","text":"
  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description session Session the Leapp Session that I want to clone"},{"location":"plugins/plugins-development/#updatesession","title":"updateSession","text":"
  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description updateSessionData SessionData the metadata used to update the given Leapp Session session Session the Leapp Session that I want to update"},{"location":"plugins/plugins-development/#openterminal","title":"openTerminal","text":"
  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description command string the command that I want to execute in the platform-specific terminal env any optional key/value env variables object"},{"location":"plugins/plugins-development/#getprofileidbyname","title":"getProfileIdByName","text":"
  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description profileName string a valid named profile"},{"location":"plugins/plugins-development/#getidpurlidbyurl","title":"getIdpUrlIdByUrl","text":"
  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description url string the URL associated with the IdpUrl I want to retrieve"},{"location":"plugins/plugins-development/#example-display-a-toast-message-in-leapp","title":"Example: display a toast message in Leapp","text":"
this.pluginEnvironment.log(\"Hello World\", LogLevel.info, true);\n
"},{"location":"plugins/plugins-development/#example-fetch-basic-usage","title":"Example: fetch basic usage","text":"
const res = await this.pluginEnvironment.fetch(\"\"); //Insert a custom URL\nconst response = await res.json();\n
"},{"location":"plugins/plugins-development/#example-open-a-url-in-the-browser","title":"Example: open a URL in the browser","text":"
this.pluginEnvironment.openExternalUrl(\"https://leapp.cloud\");\n
"},{"location":"plugins/plugins-development/#example-create-a-session","title":"Example: create a session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n\n    this.pluginEnvironment.createSession(new AwsIamRoleFederatedSessionData(\n      \"arn:aws:iam::000000000000:saml-provider/test\",\n      idpUrlId,\n      profileId,\n      \"us-east-1\",\n      \"arn:aws:iam::000000000000:role/test\",\n      \"New Name Session\"\n    ));\n}\n
"},{"location":"plugins/plugins-development/#example-edit-the-selected-session","title":"Example: edit the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n    this\n    .pluginEnvironment.updateSession(new AwsIamRoleFederatedSessionData(\n        \"arn:aws:iam::000000000000:saml-provider/test\", \n        idpUrlId, \n        profileId, \n        \"us-east-1\", \n        \"arn:aws:iam::000000000000:role/test\", \n        \"New Name Session\"\n    ), session);\n}\n
"},{"location":"plugins/plugins-development/#example-clone-the-selected-session","title":"Example: clone the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    await this.pluginEnvironment.cloneSession(session);\n}\n
"},{"location":"plugins/plugins-development/#awscredentialsplugin","title":"AwsCredentialsPlugin","text":"

A base class that needs to be extended by a plugin and serves as the action class.

After extending this class, you need to implement these methods:

"},{"location":"plugins/plugins-development/#applysessionaction","title":"applySessionAction","text":"
  • applySessionAction(session: Session, credentials: any): Promise<void>

Run your custom action

argument type description session Session the Leapp session you run the action from credentials any Leapp temporary-generated credentials

The credentials object has the following structure:

export interface CredentialsInfo {\n  sessionToken: {\n    aws_access_key_id: string;\n    aws_secret_access_key: string;\n    aws_session_token: string;\n    region: string;\n  }\n}\n
"},{"location":"plugins/plugins-development/#get-actioname","title":"get actioName","text":"
  • get actionName(): string>

Return a name for the action that will be display in Leapp (e.g. \"My Awesome Plugin\")

"},{"location":"plugins/plugins-development/#get-actionicon","title":"get actionIcon","text":"
  • get actionIcon(): string

Return a valid FontAwesome 5 code. Override default value in package.json

"},{"location":"plugins/plugins-development/#example-display-a-session-based-message-in-leapp","title":"Example: display a session-based message in Leapp","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    if(session.type === Session.awsIamUser) {\n        this.pluginEnvironment.log(`This is an IAM User session: ${session.sessionName}`, LogLevel.info, true); \n    }\n    else {\n        this.pluginEnvironment.log(`This is NOT an IAM User session: ${session.sessionName}`, LogLevel.info, true);\n    }\n}\n
"},{"location":"plugins/plugins-development/#packagejson-metadata","title":"package.json metadata","text":"property values description constraints name a custom string the name of the plugin the same used in the plugin folder author a custom string the name of the author none version a custom string the version of the plugin must be a semver string description a custom string the description of the plugin none keywords a string array the name of the plugin must contain at least \"leapp-plugin\" leappPlugin an object the plugin custom configuration must contain at least \"supportedOS\" and \"supportedSessions\" leappPlugin.supportedOS a string array [\"mac\", \"windows\", \"linux\"] if not specified, all OSs will be considered compatible leappPlugin.supportedSessions a string array [\"anyType, \"aws\", \"azure\", \"awsIamRoleFederated\", \"awsIamRoleChained\", \"awsSsoRole\", \"awsIamUser\"] at least one of these values must be specified leappPlugin.icon a custom string fontAwesome code for an icon (e.g. \"fa fa-globe\") must be a valid FontAwesome 5 code"},{"location":"plugins/plugins-development/#plugin-examples","title":"Plugin Examples","text":""},{"location":"plugins/plugins-development/#open-web-console","title":"Open Web Console","text":"
import { Session } from \"@noovolari/leapp-core/models/session\";\nimport { AwsCredentialsPlugin } from \"@noovolari/leapp-core/plugin-sdk/aws-credentials-plugin\";\nimport { PluginLogLevel } from \"@noovolari/leapp-core/plugin-sdk/plugin-log-level\";\n\nexport class WebConsolePlugin extends AwsCredentialsPlugin {\n  get actionName(): string {\n    return \"Open web console\";\n  }\n\n  get actionIcon(): string {\n    return \"fa fa-globe\";\n  }\n\n  async applySessionAction(session: Session, credentials: any): Promise<void> {\n    this.pluginEnvironment.log(\"Opening web console for session: \" + session.sessionName, PluginLogLevel.info, true);\n\n    const sessionRegion = session.region;\n    const sessionDuration = 3200;\n    const isUSGovCloud = sessionRegion.startsWith(\"us-gov-\");\n    let federationUrl;\n    let consoleHomeURL;\n\n    if (!isUSGovCloud) {\n      federationUrl = \"https://signin.aws.amazon.com/federation\";\n      consoleHomeURL = `https://${sessionRegion}.console.aws.amazon.com/console/home?region=${sessionRegion}`;\n    } else {\n      federationUrl = \"https://signin.amazonaws-us-gov.com/federation\";\n      consoleHomeURL = `https://console.amazonaws-us-gov.com/console/home?region=${sessionRegion}`;\n    }\n\n    if (sessionRegion.startsWith(\"cn-\")) {\n      throw new Error(\"Unsupported Region\");\n    }\n\n    this.pluginEnvironment.log(\"Starting opening Web Console\", PluginLogLevel.info, true);\n\n    const sessionStringJSON = {\n      sessionId: credentials.sessionToken.aws_access_key_id,\n      sessionKey: credentials.sessionToken.aws_secret_access_key,\n      sessionToken: credentials.sessionToken.aws_session_token,\n    };\n\n    const queryParametersSigninToken = `?Action=getSigninToken&SessionDuration=${sessionDuration}&Session=${encodeURIComponent(\n      JSON.stringify(sessionStringJSON)\n    )}`;\n\n    const res = await this.pluginEnvironment.fetch(`${federationUrl}${queryParametersSigninToken}`);\n    const response = await res.json();\n\n    const loginURL = `${federationUrl}?Action=login&Issuer=Leapp&Destination=${consoleHomeURL}&SigninToken=${(response as any).SigninToken}`;\n    this.pluginEnvironment.openExternalUrl(loginURL);\n  }\n}\n
"},{"location":"plugins/plugins-introduction/","title":"Introduction to Plugins","text":"

This section provides an overview of Leapp\u2019s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

"},{"location":"plugins/plugins-introduction/#add-a-plugin","title":"Add a Plugin","text":"

To add a plugin you can use one of the following methods:

"},{"location":"plugins/plugins-introduction/#add-from-npm","title":"Add from npm","text":"

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

"},{"location":"plugins/plugins-introduction/#add-manually","title":"Add manually","text":"

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

"},{"location":"plugins/plugins-introduction/#disable-a-plugin","title":"Disable a Plugin","text":"

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

"},{"location":"plugins/plugins-introduction/#remove-a-plugin","title":"Remove a Plugin","text":"

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

"},{"location":"plugins/plugins-introduction/#run-a-plugin","title":"Run a Plugin","text":"

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

"},{"location":"plugins/plugins-introduction/#plugin-menu","title":"Plugin Menu","text":"

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

"},{"location":"plugins/plugins-introduction/#create-your-plugin","title":"Create your Plugin","text":"

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             \n \u251c\u2500\u2500 package.json      # Plugin metadata\n \u2514\u2500\u2500 plugin.js         # A webpack bundle for the main logic\n

Create your Plugin

"},{"location":"security/credential-process/","title":"Credential Process","text":""},{"location":"security/credential-process/#what-is-credential-process","title":"What is Credential Process?","text":"

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the \"credential file\" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

"},{"location":"security/credential-process/#how-credential-process-works","title":"How Credential Process works?","text":"

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{\n  \"Version\": 1,\n  \"AccessKeyId\": \"an AWS access key\",\n  \"SecretAccessKey\": \"your AWS secret access key\",\n  \"SessionToken\": \"the AWS session token for temporary credentials\", \n  \"Expiration\": \"ISO8601 timestamp when the credentials expire\"\n}  \n

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

"},{"location":"security/credential-process/#advantages","title":"Advantages","text":"
  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

"},{"location":"security/credential-process/#how-leapp-works-with-credential-process","title":"How Leapp works with Credential Process","text":"

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel ().

2) In the general section change the AWS Credential Generation from \"credential-file-method\" to \"credential-process-method\".

3) An informative panel will show up telling that you need the CLI installed (see below), click on \"I acknowledge it\"

warning modal

4) Now, everytime you click on start () an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]\ncredential_process=leapp session generate SESSION_ID\nregion=REGION\n

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

"},{"location":"security/intro/","title":"Intro","text":"

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc. Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc."},{"location":"security/intro/#end-to-end-encryption","title":"End-to-end Encryption","text":"

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

"},{"location":"security/system-vault/","title":"System Vault","text":"

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

"},{"location":"security/system-vault/#supported-system-vaults","title":"Supported System Vaults","text":"OS System Vault MacOS Keychain Windows Credential Vault Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

"},{"location":"security/zero-knowledge/","title":"Zero Knowledge","text":"

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

"},{"location":"security/zero-knowledge/#users-have-key-control","title":"Users have key control","text":"

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

"},{"location":"security/zero-knowledge/#criteria","title":"Criteria","text":"
  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.
"},{"location":"security/zero-knowledge/#technologies","title":"Technologies","text":"
  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
"},{"location":"security/credentials-generation/aws/","title":"Credential file","text":"

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

"},{"location":"security/credentials-generation/aws/#iam-federated-role","title":"IAM Federated Role","text":""},{"location":"security/credentials-generation/aws/#assumerolewithsaml","title":"assumeRoleWithSAML","text":"

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

\u26a0\ufe0f In this case, generated credentials are not \"cached\" in the keychain.

"},{"location":"security/credentials-generation/aws/#iam-chained-role","title":"IAM Chained Role","text":"

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

"},{"location":"security/credentials-generation/aws/#iam-user","title":"IAM User","text":"

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

"},{"location":"security/credentials-generation/aws/#aws-sso-role","title":"AWS SSO Role","text":"

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

"},{"location":"security/credentials-generation/azure/","title":"Azure","text":""},{"location":"security/credentials-generation/azure/#azure-credentials-generation","title":"Azure credentials generation","text":"

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API. Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

"},{"location":"security/credentials-generation/azure/#access-strategy-login-integration","title":"Access strategy - login integration","text":"

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.
"},{"location":"security/credentials-generation/azure/#access-strategy-start-session","title":"Access strategy - start session","text":"

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source
"},{"location":"security/credentials-generation/azure/#access-strategy-rotate-session","title":"Access strategy - rotate session","text":"

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.
"},{"location":"security/credentials-generation/azure/#access-strategy-stop-session","title":"Access strategy - stop session","text":"

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

"},{"location":"troubleshooting/app-data/","title":"Application Data","text":""},{"location":"troubleshooting/app-data/#default-leapp-directories","title":"Default Leapp directories","text":"

Here the user can find all the directories that Leapp uses directly or indirectly.

"},{"location":"troubleshooting/app-data/#installation-path","title":"Installation path","text":"

By default, Leapp is installed in the following locations:

MacOSLinuxWindows
/Applications\n
/opt/Leapp\n
C:\\Users\\<USER>\\AppData\\Local\\Programs\\Leapp\n
"},{"location":"troubleshooting/app-data/#configuration-files","title":"Configuration files","text":"

By default, Leapp stores the configuration files in the following locations:

MacOSLinuxWindows
~/.Leapp\n
~/.Leapp\n
C:\\Users\\<USER>\\.Leapp\n

Info

  • Leapp-lock.json stores the Leapp configuration and is encrypted.
    • On startup, if Leapp-lock.json is not found, Leapp will create an empty version of it.
  • Leapp-lock.backup.bin stores a backup of Leapp-lock.json and is updated on startup if Leapp-lock.json is considered valid.
    • On startup, if Leapp-lock.json is corrupted, Leapp-lock.backup.bin will be used to restore it.
    • If both files are corrupted, a new empty configuration will be created.
  • .latest contains the latest version number of Leapp. If missing, it will be created again on startup.
"},{"location":"troubleshooting/app-data/#credentials-file","title":"Credentials file","text":"

By default, Leapp writes the credentials file in the following locations:

MacOSLinuxWindows
~/.aws\n
~/.aws\n
C:\\Users\\<USER>\\.aws\n
"},{"location":"troubleshooting/app-data/#logs-file","title":"Logs file","text":"

By default, Leapp writes logs to the following locations:

MacOSLinuxWindows
~/Library/Logs/Leapp/log.electronService.log\n
~/.config/Leapp/logs/log.electronService.log\n
C:\\Users\\<USER>\\AppData\\Roaming\\Leapp\\log.electronService.log\n

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}\n

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

"},{"location":"troubleshooting/faq/","title":"FAQ","text":""},{"location":"troubleshooting/faq/#im-using-the-open-source-app-do-you-store-my-data-online","title":"I'm using the open-source app, do you store my data online?","text":"

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

"},{"location":"troubleshooting/faq/#ive-got-a-paid-tier-how-do-you-manage-my-data-can-you-access-it","title":"I've got a paid tier, how do you manage my data? Can you access it?","text":"

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

"},{"location":"troubleshooting/faq/#i-dont-feel-secure-using-a-built-in-window-for-authentication-cant-you-use-the-default-browser","title":"I don't feel secure using a built-in window for authentication, can't you use the default browser?","text":"

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

"},{"location":"troubleshooting/faq/#how-can-i-find-leapp-data-in-the-system-vault","title":"How can I find Leapp data in the System Vault?","text":"

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

"},{"location":"troubleshooting/faq/#where-do-i-find-the-leapp-logs","title":"Where do I find the Leapp logs?","text":"

Head to the Application data section.

"},{"location":"troubleshooting/faq/#ssm-terminal-is-opening-but-no-session-is-starting-what-can-i-do","title":"SSM terminal is opening but no session is starting, what can I do?","text":"

Just close the terminal and relaunch the SSM command.

"},{"location":"troubleshooting/faq/#aws-cli-or-az-cli-is-installed-but-leapp-cant-find-it-what-can-i-do","title":"AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?","text":"

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws\nln -s /path/to/my/az /usr/local/bin/az\n
"},{"location":"troubleshooting/faq/#i-use-leapp-session-current-but-want-to-see-the-alias-and-not-the-id","title":"I use leapp session current but want to see the alias and not the id.","text":""},{"location":"troubleshooting/faq/#setting-up-leappalias-command","title":"Setting up leappalias command","text":"

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash\nleapp session current | grep -o \"\\\"alias\\\":\\\"[^\\\"]*\" | cut -d '\"' -f 4\n
  • Save the file and make it executable by running the following command in the terminal:
chmod +x leappalias.sh\n
  • Move the script to a directory in your system's PATH. For example, /usr/local/bin/:
sudo mv leappalias.sh /usr/local/bin/leappalias\n
  • Open your zshrc file using a text editor:
nano ~/.zshrc\n
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'\n
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc\n

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

"},{"location":"troubleshooting/faq/#how-can-i-add-support-to-a-new-saml-20-identity-provider","title":"How can I add support to a new SAML 2.0 Identity Provider?","text":"

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

"},{"location":"usefull-scripts/export-profile/","title":"Useful Scripts","text":""},{"location":"usefull-scripts/export-profile/#aws-profile-selector-simplifying-aws-profile-selection-with-the-leapp-cli","title":"AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI","text":"

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {\n    local selected_profile\n    selected_profile=$(leapp session list | \\\n        grep -w 'active' | \\\n        awk '{print $(NF-2)}' | \\\n        fzf --height 30% -1 -0 --header 'Select AWS profile')\n    if [[ -n \"$selected_profile\" ]]; then\n        export AWS_PROFILE=\"$selected_profile\"\n        echo \"AWS_PROFILE=$AWS_PROFILE\"\n    fi\n}\n\nalias awsp=select_and_export_aws_profile\n

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Overview","text":""},{"location":"#overview","title":"Overview","text":""},{"location":"#welcome-to-leapp","title":"Welcome to Leapp","text":"

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

"},{"location":"#introducing-leapp-cli","title":"Introducing Leapp CLI","text":"

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

"},{"location":"configuration/","title":"Add your first configuration","text":"

Now it's time to add your very first configuration. Follow the link to your preferred supported method and start enjoying Leapp.

"},{"location":"configuration/#sessions","title":"Sessions","text":""},{"location":"configuration/#aws","title":"AWS","text":"

Select the configuration you need from the Access Method dropdown menu:

Leapp Iam User

Then follow the links below.

  • Configure an AWS IAM User
  • Configure an AWS IAM Role Federated
  • Configure an AWS IAM Role Chained
  • Configure LocalStack
"},{"location":"configuration/#integrations","title":"Integrations","text":""},{"location":"configuration/#aws-sso","title":"AWS SSO","text":"
  • Configure AWS SSO
"},{"location":"configuration/#azure-ad","title":"Azure AD","text":"
  • Configure an Azure Tenant
"},{"location":"edit-session/","title":"Editing a session","text":"

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can\u2019t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select \"edit session\". A new modal will appear, allowing the user to choose which parameters to change.

edit session

Below are the configuration options for every type of session:

"},{"location":"edit-session/#iam-user","title":"Iam User","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault
"},{"location":"edit-session/#iam-role-chained","title":"IAM Role Chained","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing \"Create Chained Session\"

"},{"location":"edit-session/#iam-role-federated","title":"IAM Role Federated","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

"},{"location":"edit-session/#how-we-handle-secrets-when-editing-a-session","title":"How we handle Secrets when Editing a Session","text":"

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

"},{"location":"integrations/","title":"Integrations","text":"

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

"},{"location":"integrations/#actions","title":"Actions","text":"

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description CREATE Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions. DELETE Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.) SYNC Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status. LOGOUT Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it."},{"location":"integrations/#supported-services","title":"Supported Services","text":"Service Supported AWS SSO Okta Coming Soon OneLogin Coming Soon AzureAD"},{"location":"sessions/","title":"Sessions","text":""},{"location":"sessions/#sessions","title":"Sessions","text":"

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

"},{"location":"sessions/#actions","title":"Actions","text":"Method Description START \u00a0Make the temporary credentials available to the provider chain STOP \u00a0Removes the temporary credentials from the provider chain ROTATE \u00a0Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

"},{"location":"workspaces/","title":"Workspaces","text":""},{"location":"workspaces/#workspaces","title":"Workspaces","text":"

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

"},{"location":"workspaces/#local","title":"Local","text":"

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

"},{"location":"workspaces/#remote","title":"Remote","text":"

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

"},{"location":"workspaces/#actions","title":"Actions","text":"

The actions below only applies to Remote workspaces.

Action Description Sign-in \u00a0Connect to a Remote workspace. This action will not switch your Local workspace Switch \u00a0Switch to the selected workspace by clicking on its name in the workspace menu Lock \u00a0Switch back to the Local workspace disabling all the Remote ones Sign-out \u00a0Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

"},{"location":"built-in-features/aws-ec2-connect/","title":"Configure AWS EC2 Connect","text":""},{"location":"built-in-features/aws-ec2-connect/#what-is-aws-ec2-connect","title":"What is AWS EC2 Connect","text":"

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

"},{"location":"built-in-features/aws-ec2-connect/#how-to-configure-aws-ec2-connect-in-leapp","title":"How To configure AWS EC2 Connect in Leapp","text":"

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.
"},{"location":"built-in-features/aws-ec2-connect/#video-tutorial","title":"Video tutorial","text":"

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

"},{"location":"built-in-features/aws-named-profiles/","title":"Configure Named Profiles","text":""},{"location":"built-in-features/aws-named-profiles/#what-is-a-named-profile","title":"What is a Named Profile","text":"

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

"},{"location":"built-in-features/aws-named-profiles/#how-to-configure-a-named-profile-in-leapp","title":"How to configure a Named Profile in Leapp","text":"

Named Profiles can be created in 3 ways:

Option PanelWhen creating a new SessionEdit Profile in Contextual Menu

Click on the gear icon and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the \"Change Profile\" option in the session list.

"},{"location":"built-in-features/aws-named-profiles/#named-profile-list","title":"Named Profile List","text":"

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

"},{"location":"built-in-features/general-options/","title":"General Options","text":"

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

"},{"location":"built-in-features/general-options/#default-regions","title":"Default Regions","text":"

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

"},{"location":"built-in-features/general-options/#terminal-selection","title":"Terminal Selection","text":"

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

"},{"location":"built-in-features/general-options/#color-theme","title":"Color Theme","text":"

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

"},{"location":"built-in-features/general-options/#default-webconsole-duration","title":"Default Webconsole Duration","text":"

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

"},{"location":"built-in-features/multi-console/","title":"Configure Multi Console","text":""},{"location":"built-in-features/multi-console/#what-is-multi-console","title":"What is Multi Console","text":"

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

Get it on Firefox \u21e9 Get it on Chrome \u21e9"},{"location":"built-in-features/multi-console/#list-of-supported-browsers","title":"List of Supported Browsers","text":"Browser Supported Firefox Chrome Edge Brave Safari"},{"location":"built-in-features/multi-console/#how-to-configure-multi-console-in-leapp","title":"How to Configure Multi Console in Leapp","text":""},{"location":"built-in-features/multi-console/#install-the-extension","title":"Install the Extension","text":""},{"location":"built-in-features/multi-console/#firefox","title":"Firefox","text":"

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox \u21e9

"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers","title":"Chrome, Edge and other Chromium based browsers","text":"

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others \u21e9

"},{"location":"built-in-features/multi-console/#uninstall-the-extension","title":"Uninstall the Extension","text":""},{"location":"built-in-features/multi-console/#firefox_1","title":"Firefox","text":"
  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove
"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers_1","title":"Chrome, Edge and other Chromium based browsers","text":"
  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select \"Cookies\". Then, remove all cookies by clicking \"Remove\" until the cookie list is empty and finally click on Done

"},{"location":"built-in-features/multi-console/#how-to-use-it","title":"How to use it","text":"

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).

By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

"},{"location":"built-in-features/opening-web-console/","title":"Configure Open Web Console","text":""},{"location":"built-in-features/opening-web-console/#what-is-open-web-console","title":"What is Open Web Console","text":"

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

"},{"location":"built-in-features/opening-web-console/#how-to-configure-open-web-console-in-leapp","title":"How to Configure Open Web Console in Leapp","text":"

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

"},{"location":"cli/","title":"Index","text":"

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli\n$ leapp COMMAND\nrunning command...\n$ leapp (--version)\n@noovolari/leapp-cli/0.1.65 darwin-x64 node-v21.6.2\n$ leapp --help [COMMAND]\nUSAGE\n  $ leapp COMMAND\n...\n
"},{"location":"cli/#command-topics","title":"Command Topics","text":"
  • leapp help - Display help for leapp.
  • leapp idp-url - SAML 2.0 Identity providers URL management
  • leapp integration - Leapp Integrations management
  • leapp profile - Leapp AWS Multi-profile management
  • leapp region - Leapp regions management
  • leapp session - Sessions management
  • leapp set-workspace - Set the current Leapp workspace
  • leapp team - Login to your Team account
  • leapp version - Displays the Cli and Core versions
  • leapp workspace - Show the current workspace
"},{"location":"cli/scopes/help/","title":"Help","text":""},{"location":"cli/scopes/help/#leapp-help","title":"leapp help","text":"

Display help for leapp.

  • leapp help [COMMANDS]
"},{"location":"cli/scopes/help/#leapp-help-commands","title":"leapp help [COMMANDS]","text":"

Display help for leapp.

USAGE\n  $ leapp help [COMMANDS] [-n]\n\nARGUMENTS\n  COMMANDS  Command to show help for.\n\nFLAGS\n  -n, --nested-commands  Include all nested commands in the output.\n\nDESCRIPTION\n  Display help for leapp.\n

See code: @oclif/plugin-help

"},{"location":"cli/scopes/idp-url/","title":"Idp Url","text":""},{"location":"cli/scopes/idp-url/#leapp-idp-url","title":"leapp idp-url","text":"

SAML 2.0 Identity providers URL management

  • leapp idp-url create
  • leapp idp-url delete
  • leapp idp-url edit
  • leapp idp-url list
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-create","title":"leapp idp-url create","text":"

Create a new identity provider URL

USAGE\n  $ leapp idp-url create [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>  the idp url address we want to create\n\nDESCRIPTION\n  Create a new identity provider URL\n\nEXAMPLES\n  $leapp idp-url create\n\n  $leapp idp-url create --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-delete","title":"leapp idp-url delete","text":"

Delete an identity provider URL

USAGE\n  $ leapp idp-url delete [--idpUrlId <value>] [-f]\n\nFLAGS\n  -f, --force         force a command without asking for confirmation (-f, --force)\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Delete an identity provider URL\n\nEXAMPLES\n  $leapp idp-url delete\n\n  $leapp idp-url delete --idpUrlId ID\n\n  $leapp idp-url delete --idpUrlId ID [--force, -f]\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-edit","title":"leapp idp-url edit","text":"

Edit an identity provider URL

USAGE\n  $ leapp idp-url edit [--idpUrlId <value>] [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>    the idp url address we want to create\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Edit an identity provider URL\n\nEXAMPLES\n  $leapp idp-url edit\n\n  $leapp idp-url edit --idpUrlId ID --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-list","title":"leapp idp-url list","text":"

Show identity providers list

USAGE\n  $ leapp idp-url list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show identity providers list\n\nEXAMPLES\n  $leapp idp-url list\n
"},{"location":"cli/scopes/integration/","title":"Integration","text":""},{"location":"cli/scopes/integration/#leapp-integration","title":"leapp integration","text":"

Leapp Integrations management

  • leapp integration create
  • leapp integration delete
  • leapp integration list
  • leapp integration login
  • leapp integration logout
  • leapp integration sync
"},{"location":"cli/scopes/integration/#leapp-integration-create","title":"leapp integration create","text":"

Create a new integration

USAGE\n  $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]\n    [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]\n\nFLAGS\n  --integrationAlias=<value>      alias that identifies an integration\n  --integrationLocation=<value>   Location of an Azure Integration\n  --integrationPortalUrl=<value>  url that identifies the integration portal where you authenticate\n  --integrationRegion=<value>     an AWS valid region code for the integration\n  --integrationTenantId=<value>   Tenant ID of an Azure Integration\n  --integrationType=<option>      Identify the type of your integration. Valid types are [AWS-SSO, AZURE]\n                                  <options: AWS-SSO|AZURE>\n\nDESCRIPTION\n  Create a new integration\n\nEXAMPLES\n  $leapp integration create\n\n  $leapp integration create --integrationType AWS-SSO --integrationAlias ALIAS --integrationPortalUrl URL --integrationRegion REGION\n\n  $leapp integration create --integrationType AZURE --integrationAlias ALIAS --integrationTenantId TENANT --integrationLocation LOCATION\n
"},{"location":"cli/scopes/integration/#leapp-integration-delete","title":"leapp integration delete","text":"

Delete an integration

USAGE\n  $ leapp integration delete [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Delete an integration\n\nEXAMPLES\n  $leapp integration delete\n\n  $leapp integration delete --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-list","title":"leapp integration list","text":"

Show integrations list

USAGE\n  $ leapp integration list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show integrations list\n\nEXAMPLES\n  $leapp integration list\n
"},{"location":"cli/scopes/integration/#leapp-integration-login","title":"leapp integration login","text":"

Login to synchronize integration sessions

USAGE\n  $ leapp integration login [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Login to synchronize integration sessions\n\nEXAMPLES\n  $leapp integration login\n\n  $leapp integration login --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-logout","title":"leapp integration logout","text":"

Logout from an integration

USAGE\n  $ leapp integration logout [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Logout from an integration\n\nEXAMPLES\n  $leapp integration logout\n\n  $leapp integration logout --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-sync","title":"leapp integration sync","text":"

Synchronize integration sessions

USAGE\n  $ leapp integration sync [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Synchronize integration sessions\n\nEXAMPLES\n  $leapp integration sync\n\n  $leapp integration sync --integrationId ID\n
"},{"location":"cli/scopes/profile/","title":"Profile","text":""},{"location":"cli/scopes/profile/#leapp-profile","title":"leapp profile","text":"

Leapp AWS Multi-profile management

  • leapp profile create
  • leapp profile delete
  • leapp profile edit
  • leapp profile list
"},{"location":"cli/scopes/profile/#leapp-profile-create","title":"leapp profile create","text":"

Create a new AWS named profile

USAGE\n  $ leapp profile create [--profileName <value>]\n\nFLAGS\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Create a new AWS named profile\n\nEXAMPLES\n  $leapp profile create\n\n  $leapp profile create --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-delete","title":"leapp profile delete","text":"

Delete an AWS named profile

USAGE\n  $ leapp profile delete [--profileId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --profileId=<value>  an AWS named profile ID in Leapp\n\nDESCRIPTION\n  Delete an AWS named profile\n\nEXAMPLES\n  $leapp profile delete\n\n  $leapp profile delete --profileId PROFILEID\n\n  $leapp profile delete --profileId PROFILEID [--force, -f]\n
"},{"location":"cli/scopes/profile/#leapp-profile-edit","title":"leapp profile edit","text":"

Rename an AWS named profile

USAGE\n  $ leapp profile edit [--profileId <value>] [--profileName <value>]\n\nFLAGS\n  --profileId=<value>    an AWS named profile ID in Leapp\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Rename an AWS named profile\n\nEXAMPLES\n  $leapp profile edit\n\n  $leapp profile edit --profileId ID --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-list","title":"leapp profile list","text":"

Show profile list

USAGE\n  $ leapp profile list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show profile list\n\nEXAMPLES\n  $leapp profile list\n
"},{"location":"cli/scopes/region/","title":"Region","text":""},{"location":"cli/scopes/region/#leapp-region","title":"leapp region","text":"

Leapp regions management

  • leapp region get-default
  • leapp region set-default
"},{"location":"cli/scopes/region/#leapp-region-get-default","title":"leapp region get-default","text":"

Displays the default region

USAGE\n  $ leapp region get-default\n\nDESCRIPTION\n  Displays the default region\n\nEXAMPLES\n  $leapp region get-default\n
"},{"location":"cli/scopes/region/#leapp-region-set-default","title":"leapp region set-default","text":"

Change the default region

USAGE\n  $ leapp region set-default [--region <value>]\n\nFLAGS\n  --region=<value>  Session Region for AWS sessions in Leapp\n\nDESCRIPTION\n  Change the default region\n\nEXAMPLES\n  $leapp region set-default\n\n  $leapp region set-default --region AWSREGION\n
"},{"location":"cli/scopes/session/","title":"Session","text":""},{"location":"cli/scopes/session/#leapp-session","title":"leapp session","text":"

Sessions management

  • leapp session add
  • leapp session change-profile
  • leapp session change-region
  • leapp session current
  • leapp session delete
  • leapp session generate SESSIONID
  • leapp session get-id
  • leapp session list
  • leapp session open-web-console
  • leapp session run-aws-credential-plugin
  • leapp session start [SESSIONNAME]
  • leapp session start-ssm-session
  • leapp session stop [SESSIONNAME]
"},{"location":"cli/scopes/session/#leapp-session-add","title":"leapp session add","text":"

Add a new session

USAGE\n  $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]\n    [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]\n    [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType\n    awsIamRoleFederated|awsIamUser|awsIamRoleChained]\n\nFLAGS\n  --accessKey=<value>        AWS Access Key ID of the IAM User\n  --idpArn=<value>           AWS IAM Federated Role IdP Arn value, obtain it from your AWS Account\n  --idpUrl=<value>           the idp url address we want to create\n  --mfaDevice=<value>        MFA Device Arn retrieved from your AWS Account\n  --parentSessionId=<value>  For AWS IAM Role Chained is the session Id of the session that will assume the chained\n                             role. Retrieve it using $leapp session list -x\n  --profileId=<value>        an AWS named profile ID in Leapp\n  --providerType=<option>    Identify the provider for your sessions. Valid types are [aws]\n                             <options: aws>\n  --region=<value>           Session Region for AWS sessions in Leapp\n  --roleArn=<value>          AWS IAM Federated Role Arn value, obtain it from your AWS Account\n  --roleSessionName=<value>  Optional Alias for the Assumed Role Session name\n  --secretKey=<value>        AWS Secret Access Key of the IAM User\n  --sessionName=<value>      Session Alias to identify the session in Leapp\n  --sessionType=<option>     Identify the AWS session type. Valid types are [awsIamRoleFederated, awsIamUser,\n                             awsIamRoleChained]\n                             <options: awsIamRoleFederated|awsIamUser|awsIamRoleChained>\n\nDESCRIPTION\n  Add a new session\n\nEXAMPLES\n  $leapp session add\n\n  $leapp session add --providerType [aws] --sessionType [awsIamRoleFederated, awsIamRoleChained, awsIamUser] --region [AWSREGION] --sessionName NAME ...[combination of flags relative to the session]\n\n  $leapp session add --providerType aws --sessionType awsIamRoleFederated --sessionName NAME --region AWSREGION --idpArn IDPARN --idpUrl IDPURL --profileId PROFILEID --roleArn ROLEARN\n\n  $leapp session add --providerType aws --sessionType awsIamRoleChained --sessionName NAME --region AWSREGION --profileId PROFILEID --roleArn ROLEARN --parentSessionId ID (--roleSessionName ROLESESSIONNAME)\n\n  $leapp session add --providerType aws --sessionType awsIamUser --sessionName NAME --region AWSREGION --profileId PROFILEID --accessKey ACCESSKEY --secretKey SECRETKEY (--mfaDevice MFADEVICEARN)\n
"},{"location":"cli/scopes/session/#leapp-session-change-profile","title":"leapp session change-profile","text":"

Change a session named-profile

USAGE\n  $ leapp session change-profile [--sessionId <value>] [--profileId <value>]\n\nFLAGS\n  --profileId=<value>  an AWS named profile ID in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session named-profile\n\nEXAMPLES\n  $leapp session change-profile\n\n  $leapp session change-profile --profileId PROFILEID --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-change-region","title":"leapp session change-region","text":"

Change a session region

USAGE\n  $ leapp session change-region [--sessionId <value>] [--region <value>]\n\nFLAGS\n  --region=<value>     Session Region for AWS sessions in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session region\n\nEXAMPLES\n  $leapp session change-region\n\n  $leapp session change-region --sessionId SESSIONID --region REGION\n
"},{"location":"cli/scopes/session/#leapp-session-current","title":"leapp session current","text":"

Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile default)

USAGE\n  $ leapp session current [-i] [-p <value>] [-r aws|azure] [-f <value>]\n\nFLAGS\n  -f, --format=<value>     allows formatting data to show\n                           - aws -> id alias, accountNumber, roleArn\n                           - azure -> id tenantId, subscriptionId\n  -i, --inline\n  -p, --profile=<value>    [default: default] aws named profile of which gets info\n  -r, --provider=<option>  filters sessions by the cloud provider service\n                           <options: aws|azure>\n\nDESCRIPTION\n  Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile\n  default)\n\nEXAMPLES\n  $leapp session current --format \"alias accountNumber\" --inline --provider aws\n
"},{"location":"cli/scopes/session/#leapp-session-delete","title":"leapp session delete","text":"

Delete a session

USAGE\n  $ leapp session delete [--sessionId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Delete a session\n\nEXAMPLES\n  $leapp session delete\n\n  $leapp session delete --sessionId SESSIONID\n\n  $leapp session delete --sessionId SESSIONID [--force, -f]\n
"},{"location":"cli/scopes/session/#leapp-session-generate-sessionid","title":"leapp session generate SESSIONID","text":"

Generate STS temporary credentials for the given AWS session id

USAGE\n  $ leapp session generate SESSIONID\n\nARGUMENTS\n  SESSIONID  id of the session\n\nDESCRIPTION\n  Generate STS temporary credentials for the given AWS session id\n\nEXAMPLES\n  $leapp session generate 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d\n
"},{"location":"cli/scopes/session/#leapp-session-get-id","title":"leapp session get-id","text":"

Get session id

USAGE\n  $ leapp session get-id\n\nDESCRIPTION\n  Get session id\n\nEXAMPLES\n  $leapp session get-id\n
"},{"location":"cli/scopes/session/#leapp-session-list","title":"leapp session list","text":"

Show sessions list with all properties; filter query is case sensitive

USAGE\n  $ leapp session list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show sessions list with all properties; filter query is case sensitive\n\nEXAMPLES\n  $leapp session list\n\n  $leapp session list --filter=\"ID=Foo\" -x\n\n  $leapp session list --filter=\"Session Name=Foo\"\n\n  $leapp session list --filter=\"Type=Foo\"\n\n  $leapp session list --filter=\"Named Profile=Foo\"\n\n  $leapp session list --filter=\"Region/Location=Foo\"\n\n  $leapp session list --filter=\"Status=Foo\"\n
"},{"location":"cli/scopes/session/#leapp-session-open-web-console","title":"leapp session open-web-console","text":"

Open an AWS Web Console

USAGE\n  $ leapp session open-web-console [--sessionId <value>] [-p]\n\nFLAGS\n  -p, --print          Print an AWS Web Console login URL in the terminal instead of opening the web browser\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Open an AWS Web Console\n\nEXAMPLES\n  $leapp session open-web-console\n\n  $leapp session open-web-console --sessionId SESSIONID [--print, -p]\n
"},{"location":"cli/scopes/session/#leapp-session-run-aws-credential-plugin","title":"leapp session run-aws-credential-plugin","text":"

Run a Leapp Plugin

USAGE\n  $ leapp session run-aws-credential-plugin [--sessionId <value>] [--pluginName <value>]\n\nFLAGS\n  --pluginName=<value>  Unique name of a Leapp Plugin\n  --sessionId=<value>   Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Run a Leapp Plugin\n\nEXAMPLES\n  $leapp session run-plugin\n\n  $leapp session run-plugin --sessionName SESSIONAME --pluginName PLUGINNAME\n
"},{"location":"cli/scopes/session/#leapp-session-start-sessionname","title":"leapp session start [SESSIONNAME]","text":"

Start a session

USAGE\n  $ leapp session start [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Start a session\n\nEXAMPLES\n  $leapp session start\n\n  $leapp session start SESSIONNAME\n\n  $leapp session start SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session start SESSIONNAME --noInteractive\n\n  $leapp session start --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-start-ssm-session","title":"leapp session start-ssm-session","text":"

Start an AWS SSM session

USAGE\n  $ leapp session start-ssm-session [--sessionId <value>] [--region <value>] [--ssmInstanceId <value>]\n\nFLAGS\n  --region=<value>         Session Region for AWS sessions in Leapp\n  --sessionId=<value>      Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --ssmInstanceId=<value>  Instance ID for EC2 instance we want to access with SSM\n\nDESCRIPTION\n  Start an AWS SSM session\n\nEXAMPLES\n  $leapp session start-ssm-session\n\n  $leapp session start-ssm-session --sessionId SESSIONID --region AWSREGION --ssmInstanceId EC2INSTANCEID\n
"},{"location":"cli/scopes/session/#leapp-session-stop-sessionname","title":"leapp session stop [SESSIONNAME]","text":"

Stop a session

USAGE\n  $ leapp session stop [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Stop a session\n\nEXAMPLES\n  $leapp session stop\n\n  $leapp session stop SESSIONNAME\n\n  $leapp session stop SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session stop SESSIONNAME --noInteractive\n\n  $leapp session stop --sessionId SESSIONID\n
"},{"location":"cli/scopes/set-workspace/","title":"Set Workspace","text":""},{"location":"cli/scopes/set-workspace/#leapp-set-workspace","title":"leapp set-workspace","text":"

Set the current Leapp workspace

  • leapp set-workspace [WORKSPACENAME]
"},{"location":"cli/scopes/set-workspace/#leapp-set-workspace-workspacename","title":"leapp set-workspace [WORKSPACENAME]","text":"

Set the current Leapp workspace

USAGE\n  $ leapp set-workspace [WORKSPACENAME]\n\nARGUMENTS\n  WORKSPACENAME  name of the Leapp Team remote workspace or local\n\nDESCRIPTION\n  Set the current Leapp workspace\n\nEXAMPLES\n  $leapp team set-workspace\n\n  $leapp team set-workspace local\n\n  $leapp team set-workspace WORKSPACE-NAME\n

See code: dist/commands/set-workspace.ts

"},{"location":"cli/scopes/team/","title":"Team","text":""},{"location":"cli/scopes/team/#leapp-team","title":"leapp team","text":"

Login to your Team account

  • leapp team login
  • leapp team logout
  • leapp team status
"},{"location":"cli/scopes/team/#leapp-team-login","title":"leapp team login","text":"

Login to your Team account

USAGE\n  $ leapp team login\n\nDESCRIPTION\n  Login to your Team account\n\nEXAMPLES\n  $leapp team login\n
"},{"location":"cli/scopes/team/#leapp-team-logout","title":"leapp team logout","text":"

Logout from your Team account

USAGE\n  $ leapp team logout\n\nDESCRIPTION\n  Logout from your Team account\n\nEXAMPLES\n  $leapp team logout\n
"},{"location":"cli/scopes/team/#leapp-team-status","title":"leapp team status","text":"

Get the team login status

USAGE\n  $ leapp team status\n\nDESCRIPTION\n  Get the team login status\n\nEXAMPLES\n  $leapp team status\n
"},{"location":"cli/scopes/version/","title":"Version","text":""},{"location":"cli/scopes/version/#leapp-version","title":"leapp version","text":"

Displays the Cli and Core versions

  • leapp version
"},{"location":"cli/scopes/version/#leapp-version_1","title":"leapp version","text":"

Displays the Cli and Core versions

USAGE\n  $ leapp version\n\nDESCRIPTION\n  Displays the Cli and Core versions\n\nEXAMPLES\n  $leapp version\n

See code: dist/commands/version.ts

"},{"location":"cli/scopes/workspace/","title":"Workspace","text":""},{"location":"cli/scopes/workspace/#leapp-workspace","title":"leapp workspace","text":"

Show the current workspace

  • leapp workspace
"},{"location":"cli/scopes/workspace/#leapp-workspace_1","title":"leapp workspace","text":"

Show the current workspace

USAGE\n  $ leapp workspace\n\nDESCRIPTION\n  Show the current workspace\n\nEXAMPLES\n  $leapp workspace\n

See code: dist/commands/workspace.ts

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/","title":"Configure an AWS Identity Center (ex AWS Single Sign-On) integration","text":""},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#what-is-aws-identity-center-ex-aws-single-sign-on","title":"What is AWS Identity Center (ex AWS Single Sign-On)","text":"

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#how-to-configure-an-aws-identity-center-ex-aws-single-sign-on-integration-in-leapp","title":"How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as AWS Single Sign-on AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start. REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part."},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-integration/configure-azure-integration/","title":"Configure an Azure integration","text":""},{"location":"configuring-integration/configure-azure-integration/#what-is-an-azure-integration","title":"What is an Azure integration","text":"

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

"},{"location":"configuring-integration/configure-azure-integration/#how-to-configure-an-azure-integration-in-leapp","title":"How to configure an Azure integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-azure-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as Azure ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database. LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options."},{"location":"configuring-integration/configure-azure-integration/#video-tutorial","title":"Video tutorial","text":"

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

"},{"location":"configuring-session/configure-aws-iam-role-chained/","title":"Configure AWS IAM Role Chained","text":""},{"location":"configuring-session/configure-aws-iam-role-chained/#what-is-an-aws-iam-role-chained-session","title":"What is an AWS IAM Role Chained session","text":"

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

"},{"location":"configuring-session/configure-aws-iam-role-chained/#how-to-configure-an-aws-iam-role-chained-in-leapp","title":"How to configure an AWS IAM Role Chained in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-chained/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role. ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity. ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp."},{"location":"configuring-session/configure-aws-iam-role-chained/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/","title":"Configure AWS IAM Role Federated","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/#what-is-an-aws-iam-role-federated-session","title":"What is an AWS IAM Role Federated session","text":"

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#supported-saml-identity-providers","title":"Supported SAML Identity Providers","text":"Identity Provider AWS Azure GSUITE OKTA ONELOGIN AZURE AD AUTH0 KEYCLOAK JUMPCLOUD

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

"},{"location":"configuring-session/configure-aws-iam-role-federated/#how-to-configure-an-aws-iam-role-federated-in-leapp","title":"How to configure an AWS IAM Role Federated in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider. AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role."},{"location":"configuring-session/configure-aws-iam-role-federated/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-user/","title":"Configure AWS IAM User","text":""},{"location":"configuring-session/configure-aws-iam-user/#what-is-an-aws-iam-user-session","title":"What is an AWS IAM User session","text":"

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

"},{"location":"configuring-session/configure-aws-iam-user/#how-to-configure-an-aws-iam-user-in-leapp","title":"How to configure an AWS IAM User in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-user/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. MFA DEVICE Your MFA device ID to set up multi-factor authentication. ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. Add AWS IAM User Screen"},{"location":"configuring-session/configure-aws-iam-user/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-localstack/","title":"Configure LocalStack","text":""},{"location":"configuring-session/configure-localstack/#what-is-a-localstack-session","title":"What is a LocalStack session","text":"

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

"},{"location":"configuring-session/configure-localstack/#how-to-configure-a-localstack-session-in-leapp","title":"How to configure a LocalStack session in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

"},{"location":"contributing/get-involved/","title":"Get involved","text":""},{"location":"contributing/get-involved/#get-involved","title":"Get involved","text":"

Contributions and questions are not just welcome, they\u2019re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you\u2019re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you.

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

"},{"location":"installation/install-leapp/","title":"Install Leapp","text":""},{"location":"installation/install-leapp/#install-leapp-app","title":"Install Leapp App","text":""},{"location":"installation/install-leapp/#macos-windows-and-linux","title":"MacOS, Windows, and Linux","text":"

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp \u21e9

Unzip the package and double-click the executable to install.

"},{"location":"installation/install-leapp/#macos-homebrew","title":"macOS (Homebrew)","text":"

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp\n

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

"},{"location":"installation/install-leapp/#install-leapp-cli","title":"Install Leapp CLI","text":"

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli\n

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli\n
"},{"location":"installation/install-leapp/#install-leapp-cli-on-macos-with-arm64-chip-m1-m2","title":"Install Leapp CLI on macOS with ARM64 chip (M1, M2)","text":"

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64\n

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

"},{"location":"installation/requirements/","title":"Requirements","text":""},{"location":"installation/requirements/#requirements","title":"Requirements","text":""},{"location":"installation/requirements/#macos-and-windows","title":"MacOS and Windows","text":"

There are no requirements for macOS and Windows users.

"},{"location":"installation/requirements/#linux-systems","title":"Linux systems","text":"

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

Arch LinuxDebian/UbuntuRed Hat-based
sudo pacman -S gnome-keyring\nsudo pacman -S libsecret\n
sudo apt-get install gnome-keyring\nsudo apt-get install libsecret-1-dev\n
sudo yum install gnome-keyring\nsudo yum install libsecret-devel\n
"},{"location":"installation/requirements/#logging-into-ec2-instances-via-aws-ssm-with-leapp","title":"Logging into EC2 Instances via AWS SSM with Leapp","text":"

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>\n

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/\n

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html\n
"},{"location":"installation/update-leapp/","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#update-leapp","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#desktop-app","title":"Desktop App","text":"

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Remind me laterDownload updateClick on X

Leapp will close the modal and notify the user that a new update is available by adding a notification dot to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

"},{"location":"installation/update-leapp/#macos-homebrew-linux-linuxbrew-and-windows-via-wsl","title":"macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)","text":"

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

"},{"location":"installation/update-leapp/#cli","title":"CLI","text":"

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npmHomebrew (macOS)
npm update -g @noovolari/leapp-cli\n
brew upgrade Noovolari/brew/leapp-cli\n
"},{"location":"leapp-pro/export-pro-workspace/","title":"Export PRO Workspace","text":""},{"location":"leapp-pro/export-pro-workspace/#how-to-export-your-pro-workspace","title":"How to export your Pro Workspace","text":"
  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:\ncp Leapp-lock.json Leapp-lock.json.bkp\n
  2. log into you Pro Workspace using the Desktop App;

  3. from the Leapp Options \"General\" tab, click the button next to the \"Export Pro/Team workspace\" label;

  4. close the Leapp Options dialog;

  5. close Leapp (on macOS \u2318+Q);
  6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
  7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
    rm Leapp-lock.json\nmv Leapp-lock.json.exported Leapp-lock.json\n
  8. re-open Leapp;
  9. switch to the Local Workspace;
  10. you should now see your Pro Workspace migrated into the Local one.
"},{"location":"plugins/plugins-development/","title":"Developer Reference","text":"

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

"},{"location":"plugins/plugins-development/#pluginenvironment","title":"PluginEnvironment","text":"

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

"},{"location":"plugins/plugins-development/#log","title":"log","text":"
  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description message string the message to show level LogLevel severity of the message display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files"},{"location":"plugins/plugins-development/#fetch","title":"fetch","text":"
  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description url string a valid HTTP URL to fetch from"},{"location":"plugins/plugins-development/#openexternalurl","title":"openExternalUrl","text":"
  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description url string a valid HTTP URL to open in the default browser"},{"location":"plugins/plugins-development/#createsession","title":"createSession","text":"
  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description createSessionData SessionData the metadata used to create the Leapp Session"},{"location":"plugins/plugins-development/#clonesession","title":"cloneSession","text":"
  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description session Session the Leapp Session that I want to clone"},{"location":"plugins/plugins-development/#updatesession","title":"updateSession","text":"
  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description updateSessionData SessionData the metadata used to update the given Leapp Session session Session the Leapp Session that I want to update"},{"location":"plugins/plugins-development/#openterminal","title":"openTerminal","text":"
  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description command string the command that I want to execute in the platform-specific terminal env any optional key/value env variables object"},{"location":"plugins/plugins-development/#getprofileidbyname","title":"getProfileIdByName","text":"
  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description profileName string a valid named profile"},{"location":"plugins/plugins-development/#getidpurlidbyurl","title":"getIdpUrlIdByUrl","text":"
  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description url string the URL associated with the IdpUrl I want to retrieve"},{"location":"plugins/plugins-development/#example-display-a-toast-message-in-leapp","title":"Example: display a toast message in Leapp","text":"
this.pluginEnvironment.log(\"Hello World\", LogLevel.info, true);\n
"},{"location":"plugins/plugins-development/#example-fetch-basic-usage","title":"Example: fetch basic usage","text":"
const res = await this.pluginEnvironment.fetch(\"\"); //Insert a custom URL\nconst response = await res.json();\n
"},{"location":"plugins/plugins-development/#example-open-a-url-in-the-browser","title":"Example: open a URL in the browser","text":"
this.pluginEnvironment.openExternalUrl(\"https://leapp.cloud\");\n
"},{"location":"plugins/plugins-development/#example-create-a-session","title":"Example: create a session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n\n    this.pluginEnvironment.createSession(new AwsIamRoleFederatedSessionData(\n      \"arn:aws:iam::000000000000:saml-provider/test\",\n      idpUrlId,\n      profileId,\n      \"us-east-1\",\n      \"arn:aws:iam::000000000000:role/test\",\n      \"New Name Session\"\n    ));\n}\n
"},{"location":"plugins/plugins-development/#example-edit-the-selected-session","title":"Example: edit the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n    this\n    .pluginEnvironment.updateSession(new AwsIamRoleFederatedSessionData(\n        \"arn:aws:iam::000000000000:saml-provider/test\", \n        idpUrlId, \n        profileId, \n        \"us-east-1\", \n        \"arn:aws:iam::000000000000:role/test\", \n        \"New Name Session\"\n    ), session);\n}\n
"},{"location":"plugins/plugins-development/#example-clone-the-selected-session","title":"Example: clone the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    await this.pluginEnvironment.cloneSession(session);\n}\n
"},{"location":"plugins/plugins-development/#awscredentialsplugin","title":"AwsCredentialsPlugin","text":"

A base class that needs to be extended by a plugin and serves as the action class.

After extending this class, you need to implement these methods:

"},{"location":"plugins/plugins-development/#applysessionaction","title":"applySessionAction","text":"
  • applySessionAction(session: Session, credentials: any): Promise<void>

Run your custom action

argument type description session Session the Leapp session you run the action from credentials any Leapp temporary-generated credentials

The credentials object has the following structure:

export interface CredentialsInfo {\n  sessionToken: {\n    aws_access_key_id: string;\n    aws_secret_access_key: string;\n    aws_session_token: string;\n    region: string;\n  }\n}\n
"},{"location":"plugins/plugins-development/#get-actioname","title":"get actioName","text":"
  • get actionName(): string>

Return a name for the action that will be display in Leapp (e.g. \"My Awesome Plugin\")

"},{"location":"plugins/plugins-development/#get-actionicon","title":"get actionIcon","text":"
  • get actionIcon(): string

Return a valid FontAwesome 5 code. Override default value in package.json

"},{"location":"plugins/plugins-development/#example-display-a-session-based-message-in-leapp","title":"Example: display a session-based message in Leapp","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    if(session.type === Session.awsIamUser) {\n        this.pluginEnvironment.log(`This is an IAM User session: ${session.sessionName}`, LogLevel.info, true); \n    }\n    else {\n        this.pluginEnvironment.log(`This is NOT an IAM User session: ${session.sessionName}`, LogLevel.info, true);\n    }\n}\n
"},{"location":"plugins/plugins-development/#packagejson-metadata","title":"package.json metadata","text":"property values description constraints name a custom string the name of the plugin the same used in the plugin folder author a custom string the name of the author none version a custom string the version of the plugin must be a semver string description a custom string the description of the plugin none keywords a string array the name of the plugin must contain at least \"leapp-plugin\" leappPlugin an object the plugin custom configuration must contain at least \"supportedOS\" and \"supportedSessions\" leappPlugin.supportedOS a string array [\"mac\", \"windows\", \"linux\"] if not specified, all OSs will be considered compatible leappPlugin.supportedSessions a string array [\"anyType, \"aws\", \"azure\", \"awsIamRoleFederated\", \"awsIamRoleChained\", \"awsSsoRole\", \"awsIamUser\"] at least one of these values must be specified leappPlugin.icon a custom string fontAwesome code for an icon (e.g. \"fa fa-globe\") must be a valid FontAwesome 5 code"},{"location":"plugins/plugins-development/#plugin-examples","title":"Plugin Examples","text":""},{"location":"plugins/plugins-development/#open-web-console","title":"Open Web Console","text":"
import { Session } from \"@noovolari/leapp-core/models/session\";\nimport { AwsCredentialsPlugin } from \"@noovolari/leapp-core/plugin-sdk/aws-credentials-plugin\";\nimport { PluginLogLevel } from \"@noovolari/leapp-core/plugin-sdk/plugin-log-level\";\n\nexport class WebConsolePlugin extends AwsCredentialsPlugin {\n  get actionName(): string {\n    return \"Open web console\";\n  }\n\n  get actionIcon(): string {\n    return \"fa fa-globe\";\n  }\n\n  async applySessionAction(session: Session, credentials: any): Promise<void> {\n    this.pluginEnvironment.log(\"Opening web console for session: \" + session.sessionName, PluginLogLevel.info, true);\n\n    const sessionRegion = session.region;\n    const sessionDuration = 3200;\n    const isUSGovCloud = sessionRegion.startsWith(\"us-gov-\");\n    let federationUrl;\n    let consoleHomeURL;\n\n    if (!isUSGovCloud) {\n      federationUrl = \"https://signin.aws.amazon.com/federation\";\n      consoleHomeURL = `https://${sessionRegion}.console.aws.amazon.com/console/home?region=${sessionRegion}`;\n    } else {\n      federationUrl = \"https://signin.amazonaws-us-gov.com/federation\";\n      consoleHomeURL = `https://console.amazonaws-us-gov.com/console/home?region=${sessionRegion}`;\n    }\n\n    if (sessionRegion.startsWith(\"cn-\")) {\n      throw new Error(\"Unsupported Region\");\n    }\n\n    this.pluginEnvironment.log(\"Starting opening Web Console\", PluginLogLevel.info, true);\n\n    const sessionStringJSON = {\n      sessionId: credentials.sessionToken.aws_access_key_id,\n      sessionKey: credentials.sessionToken.aws_secret_access_key,\n      sessionToken: credentials.sessionToken.aws_session_token,\n    };\n\n    const queryParametersSigninToken = `?Action=getSigninToken&SessionDuration=${sessionDuration}&Session=${encodeURIComponent(\n      JSON.stringify(sessionStringJSON)\n    )}`;\n\n    const res = await this.pluginEnvironment.fetch(`${federationUrl}${queryParametersSigninToken}`);\n    const response = await res.json();\n\n    const loginURL = `${federationUrl}?Action=login&Issuer=Leapp&Destination=${consoleHomeURL}&SigninToken=${(response as any).SigninToken}`;\n    this.pluginEnvironment.openExternalUrl(loginURL);\n  }\n}\n
"},{"location":"plugins/plugins-introduction/","title":"Introduction to Plugins","text":"

This section provides an overview of Leapp\u2019s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

"},{"location":"plugins/plugins-introduction/#add-a-plugin","title":"Add a Plugin","text":"

To add a plugin you can use one of the following methods:

"},{"location":"plugins/plugins-introduction/#add-from-npm","title":"Add from npm","text":"

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

"},{"location":"plugins/plugins-introduction/#add-manually","title":"Add manually","text":"

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

"},{"location":"plugins/plugins-introduction/#disable-a-plugin","title":"Disable a Plugin","text":"

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

"},{"location":"plugins/plugins-introduction/#remove-a-plugin","title":"Remove a Plugin","text":"

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

"},{"location":"plugins/plugins-introduction/#run-a-plugin","title":"Run a Plugin","text":"

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

"},{"location":"plugins/plugins-introduction/#plugin-menu","title":"Plugin Menu","text":"

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

"},{"location":"plugins/plugins-introduction/#create-your-plugin","title":"Create your Plugin","text":"

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             \n \u251c\u2500\u2500 package.json      # Plugin metadata\n \u2514\u2500\u2500 plugin.js         # A webpack bundle for the main logic\n

Create your Plugin

"},{"location":"security/credential-process/","title":"Credential Process","text":""},{"location":"security/credential-process/#what-is-credential-process","title":"What is Credential Process?","text":"

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the \"credential file\" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

"},{"location":"security/credential-process/#how-credential-process-works","title":"How Credential Process works?","text":"

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{\n  \"Version\": 1,\n  \"AccessKeyId\": \"an AWS access key\",\n  \"SecretAccessKey\": \"your AWS secret access key\",\n  \"SessionToken\": \"the AWS session token for temporary credentials\", \n  \"Expiration\": \"ISO8601 timestamp when the credentials expire\"\n}  \n

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

"},{"location":"security/credential-process/#advantages","title":"Advantages","text":"
  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

"},{"location":"security/credential-process/#how-leapp-works-with-credential-process","title":"How Leapp works with Credential Process","text":"

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel ().

2) In the general section change the AWS Credential Generation from \"credential-file-method\" to \"credential-process-method\".

3) An informative panel will show up telling that you need the CLI installed (see below), click on \"I acknowledge it\"

warning modal

4) Now, everytime you click on start () an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]\ncredential_process=leapp session generate SESSION_ID\nregion=REGION\n

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

"},{"location":"security/intro/","title":"Intro","text":"

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc. Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc."},{"location":"security/intro/#end-to-end-encryption","title":"End-to-end Encryption","text":"

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

"},{"location":"security/system-vault/","title":"System Vault","text":"

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

"},{"location":"security/system-vault/#supported-system-vaults","title":"Supported System Vaults","text":"OS System Vault MacOS Keychain Windows Credential Vault Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

"},{"location":"security/zero-knowledge/","title":"Zero Knowledge","text":"

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

"},{"location":"security/zero-knowledge/#users-have-key-control","title":"Users have key control","text":"

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

"},{"location":"security/zero-knowledge/#criteria","title":"Criteria","text":"
  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.
"},{"location":"security/zero-knowledge/#technologies","title":"Technologies","text":"
  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
"},{"location":"security/credentials-generation/aws/","title":"Credential file","text":"

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

"},{"location":"security/credentials-generation/aws/#iam-federated-role","title":"IAM Federated Role","text":""},{"location":"security/credentials-generation/aws/#assumerolewithsaml","title":"assumeRoleWithSAML","text":"

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

\u26a0\ufe0f In this case, generated credentials are not \"cached\" in the keychain.

"},{"location":"security/credentials-generation/aws/#iam-chained-role","title":"IAM Chained Role","text":"

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

"},{"location":"security/credentials-generation/aws/#iam-user","title":"IAM User","text":"

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

"},{"location":"security/credentials-generation/aws/#aws-sso-role","title":"AWS SSO Role","text":"

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

"},{"location":"security/credentials-generation/azure/","title":"Azure","text":""},{"location":"security/credentials-generation/azure/#azure-credentials-generation","title":"Azure credentials generation","text":"

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API. Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

"},{"location":"security/credentials-generation/azure/#access-strategy-login-integration","title":"Access strategy - login integration","text":"

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.
"},{"location":"security/credentials-generation/azure/#access-strategy-start-session","title":"Access strategy - start session","text":"

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source
"},{"location":"security/credentials-generation/azure/#access-strategy-rotate-session","title":"Access strategy - rotate session","text":"

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.
"},{"location":"security/credentials-generation/azure/#access-strategy-stop-session","title":"Access strategy - stop session","text":"

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

"},{"location":"troubleshooting/app-data/","title":"Application Data","text":""},{"location":"troubleshooting/app-data/#default-leapp-directories","title":"Default Leapp directories","text":"

Here the user can find all the directories that Leapp uses directly or indirectly.

"},{"location":"troubleshooting/app-data/#installation-path","title":"Installation path","text":"

By default, Leapp is installed in the following locations:

MacOSLinuxWindows
/Applications\n
/opt/Leapp\n
C:\\Users\\<USER>\\AppData\\Local\\Programs\\Leapp\n
"},{"location":"troubleshooting/app-data/#configuration-files","title":"Configuration files","text":"

By default, Leapp stores the configuration files in the following locations:

MacOSLinuxWindows
~/.Leapp\n
~/.Leapp\n
C:\\Users\\<USER>\\.Leapp\n

Info

  • Leapp-lock.json stores the Leapp configuration and is encrypted.
    • On startup, if Leapp-lock.json is not found, Leapp will create an empty version of it.
  • Leapp-lock.backup.bin stores a backup of Leapp-lock.json and is updated on startup if Leapp-lock.json is considered valid.
    • On startup, if Leapp-lock.json is corrupted, Leapp-lock.backup.bin will be used to restore it.
    • If both files are corrupted, a new empty configuration will be created.
  • .latest contains the latest version number of Leapp. If missing, it will be created again on startup.
"},{"location":"troubleshooting/app-data/#credentials-file","title":"Credentials file","text":"

By default, Leapp writes the credentials file in the following locations:

MacOSLinuxWindows
~/.aws\n
~/.aws\n
C:\\Users\\<USER>\\.aws\n
"},{"location":"troubleshooting/app-data/#logs-file","title":"Logs file","text":"

By default, Leapp writes logs to the following locations:

MacOSLinuxWindows
~/Library/Logs/Leapp/log.electronService.log\n
~/.config/Leapp/logs/log.electronService.log\n
C:\\Users\\<USER>\\AppData\\Roaming\\Leapp\\log.electronService.log\n

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}\n

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

"},{"location":"troubleshooting/faq/","title":"FAQ","text":""},{"location":"troubleshooting/faq/#im-using-the-open-source-app-do-you-store-my-data-online","title":"I'm using the open-source app, do you store my data online?","text":"

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

"},{"location":"troubleshooting/faq/#ive-got-a-paid-tier-how-do-you-manage-my-data-can-you-access-it","title":"I've got a paid tier, how do you manage my data? Can you access it?","text":"

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

"},{"location":"troubleshooting/faq/#i-dont-feel-secure-using-a-built-in-window-for-authentication-cant-you-use-the-default-browser","title":"I don't feel secure using a built-in window for authentication, can't you use the default browser?","text":"

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

"},{"location":"troubleshooting/faq/#how-can-i-find-leapp-data-in-the-system-vault","title":"How can I find Leapp data in the System Vault?","text":"

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

"},{"location":"troubleshooting/faq/#where-do-i-find-the-leapp-logs","title":"Where do I find the Leapp logs?","text":"

Head to the Application data section.

"},{"location":"troubleshooting/faq/#ssm-terminal-is-opening-but-no-session-is-starting-what-can-i-do","title":"SSM terminal is opening but no session is starting, what can I do?","text":"

Just close the terminal and relaunch the SSM command.

"},{"location":"troubleshooting/faq/#aws-cli-or-az-cli-is-installed-but-leapp-cant-find-it-what-can-i-do","title":"AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?","text":"

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws\nln -s /path/to/my/az /usr/local/bin/az\n
"},{"location":"troubleshooting/faq/#i-use-leapp-session-current-but-want-to-see-the-alias-and-not-the-id","title":"I use leapp session current but want to see the alias and not the id.","text":""},{"location":"troubleshooting/faq/#setting-up-leappalias-command","title":"Setting up leappalias command","text":"

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash\nleapp session current | grep -o \"\\\"alias\\\":\\\"[^\\\"]*\" | cut -d '\"' -f 4\n
  • Save the file and make it executable by running the following command in the terminal:
chmod +x leappalias.sh\n
  • Move the script to a directory in your system's PATH. For example, /usr/local/bin/:
sudo mv leappalias.sh /usr/local/bin/leappalias\n
  • Open your zshrc file using a text editor:
nano ~/.zshrc\n
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'\n
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc\n

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

"},{"location":"troubleshooting/faq/#how-can-i-add-support-to-a-new-saml-20-identity-provider","title":"How can I add support to a new SAML 2.0 Identity Provider?","text":"

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

"},{"location":"usefull-scripts/export-profile/","title":"Useful Scripts","text":""},{"location":"usefull-scripts/export-profile/#aws-profile-selector-simplifying-aws-profile-selection-with-the-leapp-cli","title":"AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI","text":"

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {\n    local selected_profile\n    selected_profile=$(leapp session list | \\\n        grep -w 'active' | \\\n        awk '{print $(NF-2)}' | \\\n        fzf --height 30% -1 -0 --header 'Select AWS profile')\n    if [[ -n \"$selected_profile\" ]]; then\n        export AWS_PROFILE=\"$selected_profile\"\n        echo \"AWS_PROFILE=$AWS_PROFILE\"\n    fi\n}\n\nalias awsp=select_and_export_aws_profile\n

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

"}]} \ No newline at end of file diff --git a/0.25.3/security/credential-process/index.html b/0.25.3/security/credential-process/index.html index ccfa8761d..6efd8417b 100644 --- a/0.25.3/security/credential-process/index.html +++ b/0.25.3/security/credential-process/index.html @@ -1,4 +1,4 @@ - Credential Process - Leapp - Docs

Credential Process

What is Credential Process?

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the "credential file" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

How Credential Process works?

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{
+ Credential Process - Leapp - Docs      

Credential Process

What is Credential Process?

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the "credential file" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

How Credential Process works?

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{
   "Version": 1,
   "AccessKeyId": "an AWS access key",
   "SecretAccessKey": "your AWS secret access key",
@@ -8,4 +8,4 @@
 

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

Advantages

  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

How Leapp works with Credential Process

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel (option icon).

2) In the general section change the AWS Credential Generation from "credential-file-method" to "credential-process-method".

3) An informative panel will show up telling that you need the CLI installed (see below), click on "I acknowledge it"

warning modal
warning modal

4) Now, everytime you click on start (start session icon) an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]
 credential_process=leapp session generate SESSION_ID
 region=REGION
-

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

\ No newline at end of file +

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

\ No newline at end of file diff --git a/0.25.3/security/credentials-generation/aws/index.html b/0.25.3/security/credentials-generation/aws/index.html index 3734ca94a..4e32928fb 100644 --- a/0.25.3/security/credentials-generation/aws/index.html +++ b/0.25.3/security/credentials-generation/aws/index.html @@ -1 +1 @@ - Credential file - Leapp - Docs

Credential file

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

IAM Federated Role

assumeRoleWithSAML

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

⚠️ In this case, generated credentials are not "cached" in the keychain.

IAM Chained Role

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

IAM User

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

AWS SSO Role

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

\ No newline at end of file + Credential file - Leapp - Docs

Credential file

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

IAM Federated Role

assumeRoleWithSAML

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

⚠️ In this case, generated credentials are not "cached" in the keychain.

IAM Chained Role

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

IAM User

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

AWS SSO Role

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

\ No newline at end of file diff --git a/0.25.3/security/credentials-generation/azure/index.html b/0.25.3/security/credentials-generation/azure/index.html index 631d1fddc..12f80ee61 100644 --- a/0.25.3/security/credentials-generation/azure/index.html +++ b/0.25.3/security/credentials-generation/azure/index.html @@ -1 +1 @@ - Azure - Leapp - Docs

Azure

Azure credentials generation

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API.
Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

Access strategy - login integration

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.

Access strategy - start session

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source

Access strategy - rotate session

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.

Access strategy - stop session

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

\ No newline at end of file + Azure - Leapp - Docs

Azure

Azure credentials generation

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API.
Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

Access strategy - login integration

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.

Access strategy - start session

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source

Access strategy - rotate session

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.

Access strategy - stop session

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

\ No newline at end of file diff --git a/0.25.3/security/intro/index.html b/0.25.3/security/intro/index.html index 752a6adf2..a8b524292 100644 --- a/0.25.3/security/intro/index.html +++ b/0.25.3/security/intro/index.html @@ -1 +1 @@ - Intro - Leapp - Docs

Intro

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples
Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc.
Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc.

End-to-end Encryption

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

\ No newline at end of file + Intro - Leapp - Docs

Intro

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples
Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc.
Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc.

End-to-end Encryption

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

\ No newline at end of file diff --git a/0.25.3/security/system-vault/index.html b/0.25.3/security/system-vault/index.html index a426360aa..0e74366fc 100644 --- a/0.25.3/security/system-vault/index.html +++ b/0.25.3/security/system-vault/index.html @@ -1 +1 @@ - System Vault - Leapp - Docs

System Vault

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

Supported System Vaults

OS System Vault
MacOS Keychain
Windows Credential Vault
Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

\ No newline at end of file + System Vault - Leapp - Docs

System Vault

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

Supported System Vaults

OS System Vault
MacOS Keychain
Windows Credential Vault
Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

\ No newline at end of file diff --git a/0.25.3/security/zero-knowledge/index.html b/0.25.3/security/zero-knowledge/index.html index ead74708b..8e6d38d88 100644 --- a/0.25.3/security/zero-knowledge/index.html +++ b/0.25.3/security/zero-knowledge/index.html @@ -1 +1 @@ - Zero Knowledge - Leapp - Docs

Zero Knowledge

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

Users have key control

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

Criteria

  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.

Technologies

  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
\ No newline at end of file + Zero Knowledge - Leapp - Docs

Zero Knowledge

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

Users have key control

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

Criteria

  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.

Technologies

  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
\ No newline at end of file diff --git a/0.25.3/sessions/index.html b/0.25.3/sessions/index.html index b09c8951a..46dc4e054 100644 --- a/0.25.3/sessions/index.html +++ b/0.25.3/sessions/index.html @@ -1 +1 @@ - Sessions - Leapp - Docs

Sessions

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

Actions

Method Description
START  Make the temporary credentials available to the provider chain
STOP  Removes the temporary credentials from the provider chain
ROTATE  Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

\ No newline at end of file + Sessions - Leapp - Docs

Sessions

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

Actions

Method Description
START  Make the temporary credentials available to the provider chain
STOP  Removes the temporary credentials from the provider chain
ROTATE  Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

\ No newline at end of file diff --git a/0.25.3/sitemap.xml b/0.25.3/sitemap.xml index ce7e0b3f9..d7b4b9ba6 100644 --- a/0.25.3/sitemap.xml +++ b/0.25.3/sitemap.xml @@ -4,7 +4,7 @@ https://docs.leapp.cloud/latest/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -16,7 +16,7 @@ https://docs.leapp.cloud/latest/installation/requirements/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -28,7 +28,7 @@ https://docs.leapp.cloud/latest/installation/install-leapp/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -40,7 +40,7 @@ https://docs.leapp.cloud/latest/installation/update-leapp/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -52,7 +52,7 @@ https://docs.leapp.cloud/latest/sessions/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -64,7 +64,7 @@ https://docs.leapp.cloud/latest/integrations/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -76,7 +76,7 @@ https://docs.leapp.cloud/latest/workspaces/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -88,7 +88,7 @@ https://docs.leapp.cloud/latest/cli/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -100,7 +100,7 @@ https://docs.leapp.cloud/latest/cli/scopes/help/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -112,7 +112,7 @@ https://docs.leapp.cloud/latest/cli/scopes/session/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -124,7 +124,7 @@ https://docs.leapp.cloud/latest/cli/scopes/integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -136,7 +136,7 @@ https://docs.leapp.cloud/latest/cli/scopes/profile/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -148,7 +148,7 @@ https://docs.leapp.cloud/latest/cli/scopes/region/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -160,7 +160,7 @@ https://docs.leapp.cloud/latest/cli/scopes/idp-url/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -172,7 +172,7 @@ https://docs.leapp.cloud/latest/cli/scopes/set-workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -184,7 +184,7 @@ https://docs.leapp.cloud/latest/cli/scopes/workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -196,7 +196,7 @@ https://docs.leapp.cloud/latest/cli/scopes/team/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -208,7 +208,7 @@ https://docs.leapp.cloud/latest/cli/scopes/version/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -220,7 +220,7 @@ https://docs.leapp.cloud/latest/configuration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -232,7 +232,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-user/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -244,7 +244,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-role-federated/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -256,7 +256,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-role-chained/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -268,7 +268,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-localstack/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -280,7 +280,7 @@ https://docs.leapp.cloud/latest/configuring-integration/configure-aws-single-sign-on-integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -292,7 +292,7 @@ https://docs.leapp.cloud/latest/configuring-integration/configure-azure-integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -304,7 +304,7 @@ https://docs.leapp.cloud/latest/edit-session/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -316,7 +316,7 @@ https://docs.leapp.cloud/latest/security/intro/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -328,7 +328,7 @@ https://docs.leapp.cloud/latest/security/credentials-generation/aws/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -340,7 +340,7 @@ https://docs.leapp.cloud/latest/security/credential-process/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -352,7 +352,7 @@ https://docs.leapp.cloud/latest/security/credentials-generation/azure/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -364,7 +364,7 @@ https://docs.leapp.cloud/latest/security/system-vault/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -376,7 +376,7 @@ https://docs.leapp.cloud/latest/security/zero-knowledge/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -388,7 +388,7 @@ https://docs.leapp.cloud/latest/built-in-features/aws-ec2-connect/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -400,7 +400,7 @@ https://docs.leapp.cloud/latest/built-in-features/aws-named-profiles/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -412,7 +412,7 @@ https://docs.leapp.cloud/latest/built-in-features/opening-web-console/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -424,7 +424,7 @@ https://docs.leapp.cloud/latest/built-in-features/multi-console/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -436,7 +436,7 @@ https://docs.leapp.cloud/latest/plugins/plugins-introduction/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -448,7 +448,7 @@ https://docs.leapp.cloud/latest/plugins/plugins-development/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -460,79 +460,7 @@ https://docs.leapp.cloud/latest/built-in-features/general-options/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/sign-up/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/sign-in/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/lock/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/synchronization/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/security-and-password/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -544,7 +472,7 @@ https://docs.leapp.cloud/latest/leapp-pro/export-pro-workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -556,7 +484,7 @@ https://docs.leapp.cloud/latest/contributing/get-involved/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -568,7 +496,7 @@ https://docs.leapp.cloud/latest/usefull-scripts/export-profile/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -580,7 +508,7 @@ https://docs.leapp.cloud/latest/troubleshooting/app-data/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -592,7 +520,7 @@ https://docs.leapp.cloud/latest/troubleshooting/faq/ - 2024-03-29 + 2024-05-13 daily 0.9 diff --git a/0.25.3/sitemap.xml.gz b/0.25.3/sitemap.xml.gz index 9bdc30f0b..3b3e47e61 100644 Binary files a/0.25.3/sitemap.xml.gz and b/0.25.3/sitemap.xml.gz differ diff --git a/0.25.3/troubleshooting/app-data/index.html b/0.25.3/troubleshooting/app-data/index.html index ed0eb2594..11236a11a 100644 --- a/0.25.3/troubleshooting/app-data/index.html +++ b/0.25.3/troubleshooting/app-data/index.html @@ -1,4 +1,4 @@ - Application Data - Leapp - Docs

Application Data

Default Leapp directories

Here the user can find all the directories that Leapp uses directly or indirectly.

Installation path

By default, Leapp is installed in the following locations:

/Applications
+ Application Data - Leapp - Docs      

Application Data

Default Leapp directories

Here the user can find all the directories that Leapp uses directly or indirectly.

Installation path

By default, Leapp is installed in the following locations:

/Applications
 
/opt/Leapp
 
C:\Users\<USER>\AppData\Local\Programs\Leapp
 

Configuration files

By default, Leapp stores the configuration files in the following locations:

~/.Leapp
@@ -11,4 +11,4 @@
 
~/.config/Leapp/logs/log.electronService.log
 
C:\Users\<USER>\AppData\Roaming\Leapp\log.electronService.log
 

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}
-

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

\ No newline at end of file +

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

\ No newline at end of file diff --git a/0.25.3/troubleshooting/faq/index.html b/0.25.3/troubleshooting/faq/index.html index e91f08386..c96a850f3 100644 --- a/0.25.3/troubleshooting/faq/index.html +++ b/0.25.3/troubleshooting/faq/index.html @@ -1,4 +1,4 @@ - FAQ - Leapp - Docs

FAQ

I'm using the open-source app, do you store my data online?

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

I've got a paid tier, how do you manage my data? Can you access it?

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

I don't feel secure using a built-in window for authentication, can't you use the default browser?

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

How can I find Leapp data in the System Vault?

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

Where do I find the Leapp logs?

Head to the Application data section.

SSM terminal is opening but no session is starting, what can I do?

Just close the terminal and relaunch the SSM command.

AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws
+ FAQ - Leapp - Docs      

FAQ

I'm using the open-source app, do you store my data online?

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

I've got a paid tier, how do you manage my data? Can you access it?

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

I don't feel secure using a built-in window for authentication, can't you use the default browser?

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

How can I find Leapp data in the System Vault?

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

Where do I find the Leapp logs?

Head to the Application data section.

SSM terminal is opening but no session is starting, what can I do?

Just close the terminal and relaunch the SSM command.

AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws
 ln -s /path/to/my/az /usr/local/bin/az
 

I use leapp session current but want to see the alias and not the id.

Setting up leappalias command

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash
 leapp session current | grep -o "\"alias\":\"[^\"]*" | cut -d '"' -f 4
@@ -7,4 +7,4 @@
 
  • Open your zshrc file using a text editor:
nano ~/.zshrc
 
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'
 
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc
-

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

How can I add support to a new SAML 2.0 Identity Provider?

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

\ No newline at end of file +

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

How can I add support to a new SAML 2.0 Identity Provider?

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

\ No newline at end of file diff --git a/0.25.3/usefull-scripts/export-profile/index.html b/0.25.3/usefull-scripts/export-profile/index.html index 278280f2b..9b217a780 100644 --- a/0.25.3/usefull-scripts/export-profile/index.html +++ b/0.25.3/usefull-scripts/export-profile/index.html @@ -1,4 +1,4 @@ - Useful Scripts - Leapp - Docs

AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {
+ Useful Scripts - Leapp - Docs      

AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {
     local selected_profile
     selected_profile=$(leapp session list | \
         grep -w 'active' | \
@@ -11,4 +11,4 @@
 }
 
 alias awsp=select_and_export_aws_profile
-

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

\ No newline at end of file +

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

\ No newline at end of file diff --git a/0.25.3/workspaces/index.html b/0.25.3/workspaces/index.html index c936e5112..e0dd5e7f4 100644 --- a/0.25.3/workspaces/index.html +++ b/0.25.3/workspaces/index.html @@ -1 +1 @@ - Workspaces - Leapp - Docs

Workspaces

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

Local

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

Remote

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

Actions

The actions below only applies to Remote workspaces.

Action Description
Sign-in  Connect to a Remote workspace. This action will not switch your Local workspace
Switch  Switch to the selected workspace by clicking on its name in the workspace menu
Lock  Switch back to the Local workspace disabling all the Remote ones
Sign-out  Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

\ No newline at end of file + Workspaces - Leapp - Docs

Workspaces

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

Local

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

Remote

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

Actions

The actions below only applies to Remote workspaces.

Action Description
Sign-in  Connect to a Remote workspace. This action will not switch your Local workspace
Switch  Switch to the selected workspace by clicking on its name in the workspace menu
Lock  Switch back to the Local workspace disabling all the Remote ones
Sign-out  Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

\ No newline at end of file diff --git a/latest/404.html b/latest/404.html index 6d415de40..6d570d706 100644 --- a/latest/404.html +++ b/latest/404.html @@ -1 +1 @@ - Leapp - Docs
\ No newline at end of file + Leapp - Docs

The page you are looking for does not exist

404 image
\ No newline at end of file diff --git a/latest/assets/javascripts/bundle.ede584c9.min.js b/latest/assets/javascripts/bundle.13690f9d.min.js similarity index 59% rename from latest/assets/javascripts/bundle.ede584c9.min.js rename to latest/assets/javascripts/bundle.13690f9d.min.js index 172ddfce1..3221c5efd 100644 --- a/latest/assets/javascripts/bundle.ede584c9.min.js +++ b/latest/assets/javascripts/bundle.13690f9d.min.js @@ -1,3 +1,3 @@ -"use strict";(()=>{var Bi=Object.create;var _r=Object.defineProperty;var Gi=Object.getOwnPropertyDescriptor;var Ji=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Xi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,j=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ji(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Gi(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Bi(Xi(e)):{},Zi(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var mt=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[mt]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function g(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",g,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Yi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(z){try{return document.execCommand(z)}catch(C){return!1}}var d=function(C){var M=f()(C);return u("cut"),M},g=d;function L(z){var C=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(D,"px"),M.setAttribute("readonly",""),M.value=z,M}var ee=function(C,M){var D=L(C);M.container.appendChild(D);var N=f()(D);return u("copy"),D.remove(),N},ne=function(C){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,M):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,M):(D=f()(C),u("copy")),D},Z=ne;function H(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(M){return typeof M}:H=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},H(z)}var mt=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=C.action,D=M===void 0?"copy":M,N=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:N});if(G)return D==="cut"?g(G):Z(G,{container:N})},Fe=mt;function R(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(M){return typeof M}:R=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},R(z)}function se(z,C){if(!(z instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(z,C){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=R(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var G=this;this.listener=p()(N,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(N){var G=N.delegateTarget||N.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return Mr("action",N)}},{key:"defaultTarget",value:function(N){var G=Mr("target",N);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(N){return Mr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(N,G)}},{key:"cut",value:function(N){return g(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof N=="string"?[N]:N,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),M}(a()),Yi=Qi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,g){var L=p.apply(this,arguments);return l.addEventListener(u,L,g),{destroy:function(){l.removeEventListener(u,L,g)}}}function c(l,f,u,d,g){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,g)}))}function p(l,f,u,d){return function(g){g.delegateTarget=s(g.target,f),g.delegateTarget&&d.call(l,g)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,g){if(!u&&!d&&!g)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(g))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,g);if(s.nodeList(u))return l(u,d,g);if(s.string(u))return f(u,d,g);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,g){return u.addEventListener(d,g),{destroy:function(){u.removeEventListener(d,g)}}}function l(u,d,g){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,g)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,g)})}}}function f(u,d,g){return a(document.body,u,d,g)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var fs=/["'&<>]/;di.exports=us;function us(e){var t=""+e,r=fs.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function q(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function Y(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(g){f(i[0][3],g)}}function c(u){u.value instanceof ft?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Se=="function"?Se(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function P(e){return typeof e=="function"}function gt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=gt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +"use strict";(()=>{var Bi=Object.create;var _r=Object.defineProperty;var Gi=Object.getOwnPropertyDescriptor;var Ji=Object.getOwnPropertyNames,Bt=Object.getOwnPropertySymbols,Xi=Object.getPrototypeOf,Ar=Object.prototype.hasOwnProperty,uo=Object.prototype.propertyIsEnumerable;var fo=(e,t,r)=>t in e?_r(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,j=(e,t)=>{for(var r in t||(t={}))Ar.call(t,r)&&fo(e,r,t[r]);if(Bt)for(var r of Bt(t))uo.call(t,r)&&fo(e,r,t[r]);return e};var ho=(e,t)=>{var r={};for(var o in e)Ar.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Bt)for(var o of Bt(e))t.indexOf(o)<0&&uo.call(e,o)&&(r[o]=e[o]);return r};var Cr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ji(t))!Ar.call(e,n)&&n!==r&&_r(e,n,{get:()=>t[n],enumerable:!(o=Gi(t,n))||o.enumerable});return e};var Gt=(e,t,r)=>(r=e!=null?Bi(Xi(e)):{},Zi(t||!e||!e.__esModule?_r(r,"default",{value:e,enumerable:!0}):r,e));var bo=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var go=Cr((Hr,vo)=>{(function(e,t){typeof Hr=="object"&&typeof vo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(H){return!!(H&&H!==document&&H.nodeName!=="HTML"&&H.nodeName!=="BODY"&&"classList"in H&&"contains"in H.classList)}function c(H){var ft=H.type,Fe=H.tagName;return!!(Fe==="INPUT"&&s[ft]&&!H.readOnly||Fe==="TEXTAREA"&&!H.readOnly||H.isContentEditable)}function p(H){H.classList.contains("focus-visible")||(H.classList.add("focus-visible"),H.setAttribute("data-focus-visible-added",""))}function l(H){H.hasAttribute("data-focus-visible-added")&&(H.classList.remove("focus-visible"),H.removeAttribute("data-focus-visible-added"))}function f(H){H.metaKey||H.altKey||H.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(H){o=!1}function d(H){a(H.target)&&(o||c(H.target))&&p(H.target)}function g(H){a(H.target)&&(H.target.classList.contains("focus-visible")||H.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(H.target))}function L(H){document.visibilityState==="hidden"&&(n&&(o=!0),ee())}function ee(){document.addEventListener("mousemove",Z),document.addEventListener("mousedown",Z),document.addEventListener("mouseup",Z),document.addEventListener("pointermove",Z),document.addEventListener("pointerdown",Z),document.addEventListener("pointerup",Z),document.addEventListener("touchmove",Z),document.addEventListener("touchstart",Z),document.addEventListener("touchend",Z)}function ne(){document.removeEventListener("mousemove",Z),document.removeEventListener("mousedown",Z),document.removeEventListener("mouseup",Z),document.removeEventListener("pointermove",Z),document.removeEventListener("pointerdown",Z),document.removeEventListener("pointerup",Z),document.removeEventListener("touchmove",Z),document.removeEventListener("touchstart",Z),document.removeEventListener("touchend",Z)}function Z(H){H.target.nodeName&&H.target.nodeName.toLowerCase()==="html"||(o=!1,ne())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),ee(),r.addEventListener("focus",d,!0),r.addEventListener("blur",g,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var io=Cr((Vt,no)=>{(function(t,r){typeof Vt=="object"&&typeof no=="object"?no.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Vt=="object"?Vt.ClipboardJS=r():t.ClipboardJS=r()})(Vt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Yi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(z){try{return document.execCommand(z)}catch(C){return!1}}var d=function(C){var _=f()(C);return u("cut"),_},g=d;function L(z){var C=document.documentElement.getAttribute("dir")==="rtl",_=document.createElement("textarea");_.style.fontSize="12pt",_.style.border="0",_.style.padding="0",_.style.margin="0",_.style.position="absolute",_.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return _.style.top="".concat(D,"px"),_.setAttribute("readonly",""),_.value=z,_}var ee=function(C,_){var D=L(C);_.container.appendChild(D);var N=f()(D);return u("copy"),D.remove(),N},ne=function(C){var _=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=ee(C,_):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=ee(C.value,_):(D=f()(C),u("copy")),D},Z=ne;function H(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?H=function(_){return typeof _}:H=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},H(z)}var ft=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},_=C.action,D=_===void 0?"copy":_,N=C.container,G=C.target,Ue=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(G!==void 0)if(G&&H(G)==="object"&&G.nodeType===1){if(D==="copy"&&G.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(G.hasAttribute("readonly")||G.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ue)return Z(Ue,{container:N});if(G)return D==="cut"?g(G):Z(G,{container:N})},Fe=ft;function R(z){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(_){return typeof _}:R=function(_){return _&&typeof Symbol=="function"&&_.constructor===Symbol&&_!==Symbol.prototype?"symbol":typeof _},R(z)}function se(z,C){if(!(z instanceof C))throw new TypeError("Cannot call a class as a function")}function ce(z,C){for(var _=0;_0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=R(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var G=this;this.listener=p()(N,"click",function(Ue){return G.onClick(Ue)})}},{key:"onClick",value:function(N){var G=N.delegateTarget||N.currentTarget,Ue=this.action(G)||"copy",Yt=Fe({action:Ue,container:this.container,target:this.target(G),text:this.text(G)});this.emit(Yt?"success":"error",{action:Ue,text:Yt,trigger:G,clearSelection:function(){G&&G.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return Mr("action",N)}},{key:"defaultTarget",value:function(N){var G=Mr("target",N);if(G)return document.querySelector(G)}},{key:"defaultText",value:function(N){return Mr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var G=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return Z(N,G)}},{key:"cut",value:function(N){return g(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],G=typeof N=="string"?[N]:N,Ue=!!document.queryCommandSupported;return G.forEach(function(Yt){Ue=Ue&&!!document.queryCommandSupported(Yt)}),Ue}}]),_}(a()),Yi=Qi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,g){var L=p.apply(this,arguments);return l.addEventListener(u,L,g),{destroy:function(){l.removeEventListener(u,L,g)}}}function c(l,f,u,d,g){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return a(L,f,u,d,g)}))}function p(l,f,u,d){return function(g){g.delegateTarget=s(g.target,f),g.delegateTarget&&d.call(l,g)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,g){if(!u&&!d&&!g)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(g))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,g);if(s.nodeList(u))return l(u,d,g);if(s.string(u))return f(u,d,g);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,g){return u.addEventListener(d,g),{destroy:function(){u.removeEventListener(d,g)}}}function l(u,d,g){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,g)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,g)})}}}function f(u,d,g){return a(document.body,u,d,g)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";var fs=/["'&<>]/;di.exports=us;function us(e){var t=""+e,r=fs.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function q(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function B(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(g){f(i[0][3],g)}}function c(u){u.value instanceof ut?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function Eo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Oe=="function"?Oe(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function P(e){return typeof e=="function"}function xt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Xt=xt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: `+r.map(function(o,n){return n+1+") "+o.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Je(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var ze=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Se(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(P(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Se(f),d=u.next();!d.done;d=u.next()){var g=d.value;try{wo(g)}catch(L){i=i!=null?i:[],L instanceof Xt?i=Y(Y([],q(i)),q(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Je(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Je(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var $r=ze.EMPTY;function Zt(e){return e instanceof ze||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function wo(e){P(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var xt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?$r:(this.currentObservers=null,a.push(r),new ze(function(){o.currentObservers=null,Je(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(I);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:$r},t}(w);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(w);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(Tt);var $o=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(St);var Dr=new $o(ko);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=wt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(wt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(Tt);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(St);var ge=new Po(Ro);var x=new I(function(e){return e.complete()});function rr(e){return e&&P(e.schedule)}function Nr(e){return e[e.length-1]}function st(e){return P(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Ot=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return P(e==null?void 0:e.then)}function ir(e){return P(e[Et])}function ar(e){return Symbol.asyncIterator&&P(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ca(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=ca();function pr(e){return P(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ft(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ft(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ft(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return P(e==null?void 0:e.getReader)}function U(e){if(e instanceof I)return e;if(e!=null){if(ir(e))return pa(e);if(Ot(e))return la(e);if(nr(e))return ma(e);if(ar(e))return Io(e);if(pr(e))return fa(e);if(mr(e))return ua(e)}throw sr(e)}function pa(e){return new I(function(t){var r=e[Et]();if(P(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function la(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,ye(1),r?tt(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return x}:y(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new w}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,g=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,g=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return y(function(H,mt){d++,!L&&!g&&ee();var Fe=u=u!=null?u:r();mt.add(function(){d--,d===0&&!L&&!g&&(f=Br(Z,c))}),Fe.subscribe(mt),!l&&d>0&&(l=new dt({next:function(R){return Fe.next(R)},error:function(R){L=!0,ee(),f=Br(ne,n,R),Fe.error(R)},complete:function(){g=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function A(e,t=document){return Array.from(t.querySelectorAll(e))}function F(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var Ha=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),K(void 0),m(()=>Ve()||document.body),X(1));function Ke(e){return Ha.pipe(m(t=>e.contains(t)),Q())}function ot(e,t){return k(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>ke(+!r*t)):be,K(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function _t(e){let t=S("script",{src:e});return k(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),ye(1))))}var an=new w,ka=k(()=>typeof ResizeObserver=="undefined"?_t("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(Ze,$(e)).pipe(_(()=>e.disconnect()))),X(1));function ue(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(T(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ue(e)),K(ue(e)))}function At(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Qe(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe($e(0,ge),m(()=>Qe(e)),K(Qe(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ye(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe($e(0,ge),m(()=>gr(e)),K(gr(e)))}var ln=new w,$a=k(()=>$(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(Ze,$(e)).pipe(_(()=>e.disconnect()))),X(1));function Ct(e){return $a.pipe(T(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ye(e).pipe(m(({y:r})=>{let o=ue(e),n=At(e);return r>=n.height-o.height-t}),Q())}var xr={drawer:F("[data-md-toggle=drawer]"),search:F("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function nt(e,t){xr[e].checked!==t&&xr[e].click()}function Be(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),K(t.checked))}function Ra(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(K(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Ra(o,r)}return!0}),le());return Pa().pipe(b(t=>t?x:e))}function Ee(){return new URL(location.href)}function it(e,t=!1){if(B("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new w}function hn(){return location.hash.slice(1)}function bn(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),K(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>fe(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(K(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(K(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():x))}function to(e,t){return new I(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ge(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),K(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),K(wn()))}function Sn(){return V([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=V([o,r]).pipe(m(()=>Qe(e)));return V([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Ia(e){return h(e,"message",t=>t.data)}function Fa(e){let t=new w;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Ia(t),o=Fa(t),n=new w;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var ja=F("#__config"),Ht=JSON.parse(ja.textContent);Ht.base=`${new URL(Ht.base,Ee())}`;function we(){return Ht}function B(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return F(`[data-md-component=${e}]`,t)}function me(e,t=document){return A(`[data-md-component=${e}]`,t)}function Ua(e){let t=F(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>F(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!B("announce.dismiss")||!e.childElementCount)return x;if(!e.hidden){let t=F(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return k(()=>{let t=new w;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Ua(e).pipe(T(r=>t.next(r)),_(()=>t.complete()),m(r=>j({ref:e},r)))})}function Wa(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new w;return r.subscribe(({hidden:o})=>{e.hidden=o}),Wa(e,t).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))}function Dt(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return S("div",{class:"md-tooltip2",role:"dialog"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return S("div",{class:"md-tooltip2",role:"tooltip"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function Cn(e){return S("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return S("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function kn(){return S("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=we(),s=new URL(e.location,i.base);B("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=we();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function $n(e){let t=e[0].score,r=[...e],o=we(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function Rn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function Da(e){let t=we(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function In(e,t){return e=e.filter(r=>{var o;return!((o=r.properties)!=null&&o.hidden)}),S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":Me("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(Da)))}var Na=0;function Va(e,t=250){let r=V([Ke(e),ot(e,t)]).pipe(m(([n,i])=>n||i),Q()),o=k(()=>sn(e)).pipe(J(Ye),vt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>V([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Na++}`;return k(()=>{let s=new w,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>ke(+!l*250,Dr)),Q(),b(l=>l?o:x),T(l=>l.id=i),le());V([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>ot(l,250)),K(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),g=d.width/2;if(f.role==="tooltip")return{x:g,y:8+d.height};if(d.y>=u.height/2){let{height:L}=ue(f);return{x:g,y:-16-L}}else return{x:g,y:16+d.height}}));return V([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=ue(F(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Q(),xe(ge),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),V([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Va(e,r).pipe(T(l=>s.next(l)),_(()=>s.complete()),m(l=>j({ref:e},l)))})}function pt(e,{viewport$:t},r=document.body){return Nt(e,{content$:new I(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function za(e,t){let r=k(()=>V([pn(e),Ye(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=ue(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ke(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),ye(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return k(()=>{let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),Ct(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe($e(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(vt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),rt(125)).subscribe(()=>e.focus()),za(e,t).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))})}function qa(e){let t=we();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return A(r.join(", "),e)}function Ka(e){let t=[];for(let r of qa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ka(t)){let[,c]=a.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?x:k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([F(".md-typeset",f),F(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(_(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return k(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):x})}var Nn=Gt(io());var Qa=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(K(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ya(e){return Le(e).pipe(m(({width:t})=>({scrollable:At(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=k(()=>{let n=new w,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Qa++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||B("content.code.annotate"))){let g=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Q(),b(L=>L?g:x)))}}let u=A(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||B("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),g=Hn();s.push(g),B("content.tooltips")&&l.push(pt(g,{viewport$}));let L=h(g,"click").pipe(Ut(R=>!R,!1),T(()=>g.blur()),le());L.subscribe(R=>{g.classList.toggle("md-code__button--active",R)});let ee=de(u).pipe(J(R=>ot(R).pipe(m(se=>[R,se]))));L.pipe(b(R=>R?ee:x)).subscribe(([R,se])=>{let ce=fe(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let ne=de(u).pipe(J(R=>h(R,"mousedown").pipe(T(se=>se.preventDefault()),m(()=>R)))),Z=L.pipe(b(R=>R?ne:x),te(Dn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Te=A(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Te),Math.max(ce,...Te)]}})),H=Zr(x).pipe(v(R=>R.startsWith(`__codelineno-${p}-`)));H.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Te=>+Te-d+1);ce.length===1&&ce.push(ce[0]);for(let Te of A(".hll:not(.select)",e))Te.replaceWith(...Array.from(Te.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Te of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Te.childNodes).slice(1)),Te.append(je)}}),H.pipe(ye(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=de(A('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(T(se=>se.preventDefault()),m(()=>R)))).pipe(W(i),te(Dn),m(([R,se])=>{let he=+F(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Te=A(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Te),Math.max(he,...Te)]}}));O(Z,Fe).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),B("content.tooltips")&&l.push(pt(d,{viewport$}))}if(s.length){let d=kn();d.append(...s),a.insertBefore(d,e)}return Ya(e).pipe(T(d=>n.next(d)),_(()=>n.complete()),m(d=>j({ref:e},d)),Ne(O(...l).pipe(W(i))))});return B("content.lazy")?Ct(e).pipe(v(n=>n),ye(1),b(()=>o)):o}function Ba(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return k(()=>{let r=new w;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ba(e,t).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function Ga(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Ja(e,t){for(let r of A("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}return $(e)}function Kn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return x;if(!(B("navigation.instant.preview")||e.hasAttribute("data-preview")))return x;let o=V([Ke(e),ot(e)]).pipe(m(([i,s])=>i||s),Q(),v(i=>i));return ht([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?$(s):x}),b(i=>yr(i).pipe(b(s=>Ja(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=fe(s,i);return typeof a=="undefined"?x:$(Ga(a))})).pipe(b(i=>{let s=new I(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,j({content$:s},t))}))}var Qn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,Za=0;function es(){return typeof mermaid=="undefined"||mermaid instanceof Element?_t("https://unpkg.com/mermaid@10.7.0/dist/mermaid.min.js"):$(void 0)}function Yn(e){return e.classList.remove("mermaid"),ao||(ao=es().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Qn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Za++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Bn=S("table");function Gn(e){return e.replaceWith(Bn),Bn.replaceWith(Pn(e)),$({ref:e})}function ts(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>F(`label[for="${r.id}"]`))))).pipe(K(F(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Jn(e,{viewport$:t,target$:r}){let o=F(".tabbed-labels",e),n=A(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),k(()=>{let a=new w,c=a.pipe(re(),ae(!0));V([a,Le(e)]).pipe(W(c),$e(1,ge)).subscribe({next([{active:p},l]){let f=Qe(p),{width:u}=ue(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),V([Ye(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=At(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=ue(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=F(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let g of A("[data-tabs]"))for(let L of A(":scope > input",g)){let ee=F(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of A("audio, video",e))p.pause()}),ts(n).pipe(T(p=>a.next(p)),_(()=>a.complete()),m(p=>j({ref:e},p)))}).pipe(Xe(pe))}function Xn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...A(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...A("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...A("a:not([title])",e).map(i=>Kn(i,t)),...A("pre.mermaid",e).map(i=>Yn(i)),...A("table:not([class])",e).map(i=>Gn(i)),...A("details",e).map(i=>qn(i,{target$:o,print$:n})),...A("[data-tabs]",e).map(i=>Jn(i,{viewport$:r,target$:o})),...A("[title]",e).filter(()=>B("content.tooltips")).map(i=>pt(i,{viewport$:r})),...A(".footnote-ref",e).filter(()=>B("content.footnote.tooltips")).map(i=>Nt(i,{content$:new I(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function rs(e,{alert$:t}){return t.pipe(b(r=>O($(!0),$(!1).pipe(rt(2e3))).pipe(m(o=>({message:r,active:o})))))}function Zn(e,t){let r=F(".md-typeset",e);return k(()=>{let o=new w;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),rs(e,t).pipe(T(n=>o.next(n)),_(()=>o.complete()),m(n=>j({ref:e},n)))})}var os=0;function ns(e,t){document.body.append(e);let{width:r}=ue(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ye(o):$({x:0,y:0}),i=O(Ke(t),ot(t)).pipe(Q());return V([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Qe(t),l=ue(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ei(e){let t=e.title;if(!t.length)return x;let r=`__tooltip_${os++}`,o=Dt(r,"inline"),n=F(".md-typeset",o);return n.innerHTML=t,k(()=>{let i=new w;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe($e(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(vt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),ns(o,e).pipe(T(s=>i.next(s)),_(()=>i.complete()),m(s=>j({ref:e},s)))}).pipe(Xe(pe))}function is({viewport$:e}){if(!B("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),et(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Q()),o=Be("search");return V([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Q(),b(n=>n?r:$(!1)),K(!1))}function ti(e,t){return k(()=>V([Le(e),is(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Q((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function ri(e,{header$:t,main$:r}){return k(()=>{let o=new w,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=de(A("[title]",e)).pipe(v(()=>B("content.tooltips")),J(s=>ei(s)));return r.subscribe(o),t.pipe(W(n),m(s=>j({ref:e},s)),Ne(i.pipe(W(n))))})}function as(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ue(e);return{active:o>=n}}),oe("active"))}function oi(e,t){return k(()=>{let r=new w;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?x:as(o,t).pipe(T(n=>r.next(n)),_(()=>r.complete()),m(n=>j({ref:e},n)))})}function ni(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Q()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return V([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Q((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function ss(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),K(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ii(e){let t=A("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return k(()=>{let i=new w;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),ss(t).pipe(W(n.pipe(Pe(1))),bt(),T(s=>i.next(s)),_(()=>i.complete()),m(s=>j({ref:e},s)))})}function ai(e,{progress$:t}){return k(()=>{let r=new w;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}function si(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function cs(e,t){let r=new Map;for(let o of A("url",e)){let n=F("loc",o),i=[si(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of A("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(si(new URL(a),t))}}return r}function kt(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>cs(t,new URL(e))),Oe(()=>$(new Map)),le())}function ci({document$:e}){let t=new Map;e.pipe(b(()=>A("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>kt(r).pipe(m(o=>[r,o])))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(f));if(typeof n=="undefined")return x;let[i,s]=n,a=Ee();if(a.href.startsWith(i))return x;let c=we(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),$(l)}}return x})).subscribe(r=>it(r,!0))}var so=Gt(io());function ps(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function pi({alert$:e}){so.default.isSupported()&&new I(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ps(F(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function li(e,t){if(!(e.target instanceof Element))return x;let r=e.target.closest("a");if(r===null)return x;if(r.target||e.metaKey||e.ctrlKey)return x;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(r)):x}function mi(e){let t=new Map;for(let r of A(":scope > *",e.head))t.set(r.outerHTML,r);return t}function fi(e){for(let t of A("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function ls(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=mi(document);for(let[o,n]of mi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return qe(A("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new I(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),x}),re(),ae(document))}function ui({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return x;$(document).subscribe(fi);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>li(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(Ee),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(Oe(()=>(it(a,!0),x)))),b(fi),b(ls),le());return O(s.pipe(te(t,(a,c)=>c)),t.pipe(oe("pathname"),b(()=>t),oe("hash")),t.pipe(Q((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),T(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),B("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>li(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),ye(1))})).subscribe(a=>a.remove()),s}var bi=Gt(hi());function vi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,bi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function gi(e,t){let r=On(e);return O($(location.protocol!=="file:"),Be("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function xi({document$:e}){let t=we(),r=Ge(new URL("../versions.json",t.base)).pipe(Oe(()=>x)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?x:(i.preventDefault(),$(c))}}return x}),b(i=>{let{version:s}=n.get(i);return kt(new URL(i)).pipe(m(a=>{let p=Ee().href.replace(t.base,"");return a.has(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>it(n,!0)),V([r,o]).subscribe(([n,i])=>{F(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function hs(e,{worker$:t}){let{searchParams:r}=Ee();r.has("q")&&(nt("search",!0),e.value=r.get("q"),e.focus(),Be("search").pipe(Re(i=>!i)).subscribe(()=>{let i=Ee();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ke(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Q());return V([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function yi(e,{worker$:t}){let r=new w,o=r.pipe(re(),ae(!0));V([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&nt("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=F("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),hs(e,{worker$:t}).pipe(T(i=>r.next(i)),_(()=>r.complete()),m(i=>j({ref:e},i)),X(1))}function Ei(e,{worker$:t,query$:r}){let o=new w,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=F(":scope > :first-child",e),a=F(":scope > :last-child",e);Be("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),b(({items:l})=>O($(...l.slice(0,10)),$(...l.slice(10)).pipe(et(4),Xr(n),b(([f])=>f)))),m($n),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=fe("details",l);return typeof f=="undefined"?x:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),_(()=>o.complete()),m(l=>j({ref:e},l)))}function bs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=Ee();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function wi(e,t){let r=new w,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),bs(e,t).pipe(T(n=>r.next(n)),_(()=>r.complete()),m(n=>j({ref:e},n)))}function Ti(e,{worker$:t,keyboard$:r}){let o=new w,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Q());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),_(()=>o.complete()),m(()=>({ref:e})))}function Si(e,{index$:t,keyboard$:r}){let o=we();try{let n=gi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>nt("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of A(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":nt("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...A(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=yi(i,{worker$:n});return O(a,Ei(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>wi(c,{query$:a})),...me("search-suggest",e).map(c=>Ti(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ze}}function Oi(e,{index$:t,location$:r}){return V([t,r.pipe(K(Ee()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>vi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function vs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return V([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Q((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=F(".md-sidebar__scrollwrap",e),{y:s}=Qe(i);return k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=a.pipe($e(0,ge));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of A(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ue(f);f.scrollTo({top:u-d/2})}}}),de(A("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),W(c)))).subscribe(l=>{let f=F(`[id="${l.htmlFor}"]`);F(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),vs(e,r).pipe(T(l=>a.next(l)),_(()=>a.complete()),m(l=>j({ref:e},l)))})}function Li(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return ht(Ge(`${r}/releases/latest`).pipe(Oe(()=>x),m(o=>({version:o.tag_name})),tt({})),Ge(r).pipe(Oe(()=>x),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),tt({}))).pipe(m(([o,n])=>j(j({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(m(o=>({repositories:o.public_repos})),tt({}))}}function Mi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(Oe(()=>x),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),tt({}))}function _i(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Li(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Mi(r,o)}return x}var gs;function xs(e){return gs||(gs=k(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return x}return _i(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(Oe(()=>x),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ai(e){let t=F(":scope > :last-child",e);return k(()=>{let r=new w;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),xs(e).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function ys(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Ci(e,t){return k(()=>{let r=new w;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?$({hidden:!1}):ys(e,t)).pipe(T(o=>r.next(o)),_(()=>r.complete()),m(o=>j({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){let o=new Map,n=A(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=fe(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=F(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>k(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let g=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!g)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Q((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),K({prev:[],next:[]}),et(2,1),m(([a,c])=>a.prev.length{let i=new w,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),B("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ue(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return B("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),bt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=Ee(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Es(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))})}function ws(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),et(2,1),m(([s,a])=>s>a&&a>0),Q()),i=r.pipe(m(({active:s})=>s));return V([i,n]).pipe(m(([s,a])=>!(s&&a)),Q(),W(o.pipe(Pe(1))),ae(!0),bt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),ws(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),_(()=>i.complete()),m(a=>j({ref:e},a)))}function $i({document$:e,viewport$:t}){e.pipe(b(()=>A(".md-ellipsis")),J(r=>Ct(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),ye(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,pt(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),_(()=>n.removeAttribute("title")))})).subscribe(),e.pipe(b(()=>A(".md-status")),J(r=>pt(r,{viewport$:t}))).subscribe()}function Ri({document$:e,tablet$:t}){e.pipe(b(()=>A(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ts(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Pi({document$:e}){e.pipe(b(()=>A("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ts),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ii({viewport$:e,tablet$:t}){V([Be("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(rt(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ss(){return location.protocol==="file:"?_t(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):Ge(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var at=on(),Kt=dn(),$t=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),ji=Wt("(min-width: 1220px)"),Ui=gn(),Or=we(),Wi=document.forms.namedItem("search")?Ss():Ze,lo=new w;pi({alert$:lo});ci({document$:at});var mo=new w,Di=kt(Or.base);B("navigation.instant")&&ui({sitemap$:Di,location$:Kt,viewport$:He,progress$:mo}).subscribe(at);var Fi;((Fi=Or.version)==null?void 0:Fi.provider)==="mike"&&xi({document$:at});O(Kt,$t).pipe(rt(125)).subscribe(()=>{nt("drawer",!1),nt("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&&it(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&&it(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});$i({viewport$:He,document$:at});Ri({document$:at,tablet$:Lr});Pi({document$:at});Ii({viewport$:He,tablet$:Lr});var lt=ti(Ce("header"),{viewport$:He}),qt=at.pipe(m(()=>Ce("main")),b(e=>ni(e,{viewport$:He,header$:lt})),X(1)),Os=O(...me("consent").map(e=>Mn(e,{target$:$t})),...me("dialog").map(e=>Zn(e,{alert$:lo})),...me("header").map(e=>ri(e,{viewport$:He,header$:lt,main$:qt})),...me("palette").map(e=>ii(e)),...me("progress").map(e=>ai(e,{progress$:mo})),...me("search").map(e=>Si(e,{index$:Wi,keyboard$:po})),...me("source").map(e=>Ai(e))),Ls=k(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Xn(e,{sitemap$:Di,viewport$:He,target$:$t,print$:Ui})),...me("content").map(e=>B("search.highlight")?Oi(e,{index$:Wi,location$:Kt}):x),...me("header-title").map(e=>oi(e,{viewport$:He,header$:lt})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(ji,()=>co(e,{viewport$:He,header$:lt,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:lt,main$:qt}))),...me("tabs").map(e=>Ci(e,{viewport$:He,header$:lt})),...me("toc").map(e=>Hi(e,{viewport$:He,header$:lt,main$:qt,target$:$t})),...me("top").map(e=>ki(e,{viewport$:He,header$:lt,main$:qt,target$:$t})))),Ni=at.pipe(b(()=>Ls),Ne(Os),X(1));Ni.subscribe();window.document$=at;window.location$=Kt;window.target$=$t;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=ji;window.print$=Ui;window.alert$=lo;window.progress$=mo;window.component$=Ni;})(); + `):"",this.name="UnsubscriptionError",this.errors=r}});function Xe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var ze=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Oe(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(L){t={error:L}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(P(l))try{l()}catch(L){i=L instanceof Xt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=Oe(f),d=u.next();!d.done;d=u.next()){var g=d.value;try{wo(g)}catch(L){i=i!=null?i:[],L instanceof Xt?i=B(B([],q(i)),q(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Xt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)wo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Xe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Xe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var $r=ze.EMPTY;function Zt(e){return e instanceof ze||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function wo(e){P(e)?e():e.unsubscribe()}var We={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var yt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?$r:(this.currentObservers=null,a.push(r),new ze(function(){o.currentObservers=null,Xe(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(I);var Co=function(e){ie(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:$r},t}(w);var jr=function(e){ie(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(w);var Pt={now:function(){return(Pt.delegate||Date).now()},delegate:void 0};var It=function(e){ie(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=Pt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(St);var $o=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(Ot);var Dr=new $o(ko);var Ro=function(e){ie(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Tt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(Tt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(St);var Po=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(Ot);var ge=new Po(Ro);var x=new I(function(e){return e.complete()});function rr(e){return e&&P(e.schedule)}function Nr(e){return e[e.length-1]}function ct(e){return P(Nr(e))?e.pop():void 0}function Ie(e){return rr(Nr(e))?e.pop():void 0}function or(e,t){return typeof Nr(e)=="number"?e.pop():t}var Lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function nr(e){return P(e==null?void 0:e.then)}function ir(e){return P(e[wt])}function ar(e){return Symbol.asyncIterator&&P(e==null?void 0:e[Symbol.asyncIterator])}function sr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ca(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var cr=ca();function pr(e){return P(e==null?void 0:e[cr])}function lr(e){return yo(this,arguments,function(){var r,o,n,i;return Jt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ut(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ut(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ut(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function mr(e){return P(e==null?void 0:e.getReader)}function U(e){if(e instanceof I)return e;if(e!=null){if(ir(e))return pa(e);if(Lt(e))return la(e);if(nr(e))return ma(e);if(ar(e))return Io(e);if(pr(e))return fa(e);if(mr(e))return ua(e)}throw sr(e)}function pa(e){return new I(function(t){var r=e[wt]();if(P(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function la(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):be,Ee(1),r?rt(t):Zo(function(){return new ur}))}}function Yr(e){return e<=0?function(){return x}:y(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function le(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new w}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,g=!1,L=!1,ee=function(){f==null||f.unsubscribe(),f=void 0},ne=function(){ee(),l=u=void 0,g=L=!1},Z=function(){var H=l;ne(),H==null||H.unsubscribe()};return y(function(H,ft){d++,!L&&!g&&ee();var Fe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!g&&(f=Br(Z,c))}),Fe.subscribe(ft),!l&&d>0&&(l=new ht({next:function(R){return Fe.next(R)},error:function(R){L=!0,ee(),f=Br(ne,n,R),Fe.error(R)},complete:function(){g=!0,ee(),f=Br(ne,s),Fe.complete()}}),U(H).subscribe(l))})(p)}}function Br(e,t){for(var r=[],o=2;oe.next(document)),e}function M(e,t=document){return Array.from(t.querySelectorAll(e))}function F(e,t=document){let r=ue(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ue(e,t=document){return t.querySelector(e)||void 0}function Ve(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var Ha=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(Ae(1),K(void 0),m(()=>Ve()||document.body),X(1));function Ke(e){return Ha.pipe(m(t=>e.contains(t)),Y())}function nt(e,t){return k(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?jt(r=>ke(+!r*t)):be,K(e.matches(":hover"))))}function nn(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)nn(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)nn(o,n);return o}function br(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function At(e){let t=S("script",{src:e});return k(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(b(()=>Vr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),Ee(1))))}var an=new w,ka=k(()=>typeof ResizeObserver=="undefined"?At("https://unpkg.com/resize-observer-polyfill"):$(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>an.next(t)))),b(e=>O(et,$(e)).pipe(A(()=>e.disconnect()))),X(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Le(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return ka.pipe(T(r=>r.observe(t)),b(r=>an.pipe(v(o=>o.target===t),A(()=>r.unobserve(t)))),m(()=>de(e)),K(de(e)))}function Ct(e){return{width:e.scrollWidth,height:e.scrollHeight}}function vr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function sn(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Qe(e){return{x:e.offsetLeft,y:e.offsetTop}}function cn(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function pn(e){return O(h(window,"load"),h(window,"resize")).pipe($e(0,ge),m(()=>Qe(e)),K(Qe(e)))}function gr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ye(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe($e(0,ge),m(()=>gr(e)),K(gr(e)))}var ln=new w,$a=k(()=>$(new IntersectionObserver(e=>{for(let t of e)ln.next(t)},{threshold:0}))).pipe(b(e=>O(et,$(e)).pipe(A(()=>e.disconnect()))),X(1));function lt(e){return $a.pipe(T(t=>t.observe(e)),b(t=>ln.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function mn(e,t=16){return Ye(e).pipe(m(({y:r})=>{let o=de(e),n=Ct(e);return r>=n.height-o.height-t}),Y())}var xr={drawer:F("[data-md-toggle=drawer]"),search:F("[data-md-toggle=search]")};function fn(e){return xr[e].checked}function it(e,t){xr[e].checked!==t&&xr[e].click()}function Be(e){let t=xr[e];return h(t,"change").pipe(m(()=>t.checked),K(t.checked))}function Ra(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Pa(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(K(!1))}function un(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:fn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ve();if(typeof o!="undefined")return!Ra(o,r)}return!0}),le());return Pa().pipe(b(t=>t?x:e))}function we(){return new URL(location.href)}function at(e,t=!1){if(Q("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function dn(){return new w}function hn(){return location.hash.slice(1)}function bn(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Zr(e){return O(h(window,"hashchange"),e).pipe(m(hn),K(hn()),v(t=>t.length>0),X(1))}function vn(e){return Zr(e).pipe(m(t=>ue(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function Wt(e){let t=matchMedia(e);return dr(r=>t.addListener(()=>r(t.matches))).pipe(K(t.matches))}function gn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(K(e.matches))}function eo(e,t){return e.pipe(b(r=>r?t():x))}function to(e,t){return new I(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let s=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+s*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function Ge(e,t){return to(e,t).pipe(b(r=>r.text()),m(r=>JSON.parse(r)),X(1))}function yr(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),X(1))}function xn(e,t){let r=new DOMParser;return to(e,t).pipe(b(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),X(1))}function yn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function En(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(yn),K(yn()))}function wn(){return{width:innerWidth,height:innerHeight}}function Tn(){return h(window,"resize",{passive:!0}).pipe(m(wn),K(wn()))}function Sn(){return V([En(),Tn()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function Er(e,{viewport$:t,header$:r}){let o=t.pipe(oe("size")),n=V([o,r]).pipe(m(()=>Qe(e)));return V([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function Ia(e){return h(e,"message",t=>t.data)}function Fa(e){let t=new w;return t.subscribe(r=>e.postMessage(r)),t}function On(e,t=new Worker(e)){let r=Ia(t),o=Fa(t),n=new w;n.subscribe(o);let i=o.pipe(re(),ae(!0));return n.pipe(re(),Ne(r.pipe(W(i))),le())}var ja=F("#__config"),Ht=JSON.parse(ja.textContent);Ht.base=`${new URL(Ht.base,we())}`;function Te(){return Ht}function Q(e){return Ht.features.includes(e)}function Me(e,t){return typeof t!="undefined"?Ht.translations[e].replace("#",t.toString()):Ht.translations[e]}function Ce(e,t=document){return F(`[data-md-component=${e}]`,t)}function me(e,t=document){return M(`[data-md-component=${e}]`,t)}function Ua(e){let t=F(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>F(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function Ln(e){if(!Q("announce.dismiss")||!e.childElementCount)return x;if(!e.hidden){let t=F(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return k(()=>{let t=new w;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Ua(e).pipe(T(r=>t.next(r)),A(()=>t.complete()),m(r=>j({ref:e},r)))})}function Wa(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Mn(e,t){let r=new w;return r.subscribe(({hidden:o})=>{e.hidden=o}),Wa(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))}function Dt(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function wr(...e){return S("div",{class:"md-tooltip2",role:"dialog"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function _n(...e){return S("div",{class:"md-tooltip2",role:"tooltip"},S("div",{class:"md-tooltip2__inner md-typeset"},e))}function An(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Dt(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function Cn(e){return S("button",{class:"md-code__button",title:Me("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function Hn(){return S("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function kn(){return S("nav",{class:"md-code__nav"})}function ro(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=Te(),s=new URL(e.location,i.base);Q("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=Te();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},Me("search.result.term.missing"),": ",...n)))}function $n(e){let t=e[0].score,r=[...e],o=Te(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scorero(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?Me("search.result.more.one"):Me("search.result.more.other",c.length))),...c.map(l=>ro(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function Rn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?br(r):r)))}function oo(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function Pn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function Da(e){let t=Te(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function In(e,t){return e=e.filter(r=>{var o;return!((o=r.properties)!=null&&o.hidden)}),S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":Me("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(Da)))}var Na=0;function Va(e,t=250){let r=V([Ke(e),nt(e,t)]).pipe(m(([n,i])=>n||i),Y()),o=k(()=>sn(e)).pipe(J(Ye),gt(1),m(()=>cn(e)));return r.pipe(Re(n=>n),b(()=>V([r,o])),m(([n,i])=>({active:n,offset:i})),le())}function Nt(e,t,r=250){let{content$:o,viewport$:n}=t,i=`__tooltip2_${Na++}`;return k(()=>{let s=new w,a=new jr(!1);s.pipe(re(),ae(!1)).subscribe(a);let c=a.pipe(jt(l=>ke(+!l*250,Dr)),Y(),b(l=>l?o:x),T(l=>l.id=i),le());V([s.pipe(m(({active:l})=>l)),c.pipe(b(l=>nt(l,250)),K(!1))]).pipe(m(l=>l.some(f=>f))).subscribe(a);let p=a.pipe(v(l=>l),te(c,n),m(([l,f,{size:u}])=>{let d=e.getBoundingClientRect(),g=d.width/2;if(f.role==="tooltip")return{x:g,y:8+d.height};if(d.y>=u.height/2){let{height:L}=de(f);return{x:g,y:-16-L}}else return{x:g,y:16+d.height}}));return V([c,s,p]).subscribe(([l,{offset:f},u])=>{l.style.setProperty("--md-tooltip-host-x",`${f.x}px`),l.style.setProperty("--md-tooltip-host-y",`${f.y}px`),l.style.setProperty("--md-tooltip-x",`${u.x}px`),l.style.setProperty("--md-tooltip-y",`${u.y}px`),l.classList.toggle("md-tooltip2--top",u.y<0),l.classList.toggle("md-tooltip2--bottom",u.y>=0)}),a.pipe(v(l=>l),te(c,(l,f)=>f),v(l=>l.role==="tooltip")).subscribe(l=>{let f=de(F(":scope > *",l));l.style.setProperty("--md-tooltip-width",`${f.width}px`),l.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(Y(),xe(ge),te(c)).subscribe(([l,f])=>{f.classList.toggle("md-tooltip2--active",l)}),V([a.pipe(v(l=>l)),c]).subscribe(([l,f])=>{f.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),a.pipe(v(l=>!l)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Va(e,r).pipe(T(l=>s.next(l)),A(()=>s.complete()),m(l=>j({ref:e},l)))})}function Je(e,{viewport$:t},r=document.body){return Nt(e,{content$:new I(o=>{let n=e.title,i=_n(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t},0)}function za(e,t){let r=k(()=>V([pn(e),Ye(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=de(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return Ke(e).pipe(b(o=>r.pipe(m(n=>({active:o,offset:n})),Ee(+!o||1/0))))}function Fn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return k(()=>{let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),lt(e).pipe(W(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),O(i.pipe(v(({active:a})=>a)),i.pipe(Ae(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe($e(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(W(s),te(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ve())==null||p.blur()}}),r.pipe(W(s),v(a=>a===o),ot(125)).subscribe(()=>e.focus()),za(e,t).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function qa(e){let t=Te();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(typeof t.annotate!="undefined"){let o=e.closest("[class|=language]");if(o)for(let n of Array.from(o.classList)){if(!n.startsWith("language-"))continue;let[,i]=n.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return M(r.join(", "),e)}function Ka(e){let t=[];for(let r of qa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function jn(e,t){t.append(...Array.from(e.childNodes))}function Tr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Ka(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ue(`:scope > li:nth-child(${c})`,e)&&(s.set(c,An(c,i)),a.replaceWith(s.get(c)))}return s.size===0?x:k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=[];for(let[l,f]of s)p.push([F(".md-typeset",f),F(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?jn(f,u):jn(u,f)}),O(...[...s].map(([,l])=>Fn(l,t,{target$:r}))).pipe(A(()=>a.complete()),le())})}function Un(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Un(t)}}function Wn(e,t){return k(()=>{let r=Un(e);return typeof r!="undefined"?Tr(r,e,t):x})}var Nn=Gt(io());var Qa=0,Dn=O(h(window,"keydown").pipe(m(()=>!0)),O(h(window,"keyup"),h(window,"contextmenu")).pipe(m(()=>!1))).pipe(K(!1),X(1));function Vn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Vn(t)}}function Ya(e){return Le(e).pipe(m(({width:t})=>({scrollable:Ct(e).width>t})),oe("scrollable"))}function zn(e,t){let{matches:r}=matchMedia("(hover)"),o=k(()=>{let n=new w,i=n.pipe(Yr(1));n.subscribe(({scrollable:d})=>{d&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[],a=e.closest("pre"),c=a.closest("[id]"),p=c?c.id:Qa++;a.id=`__code_${p}`;let l=[],f=e.closest(".highlight");if(f instanceof HTMLElement){let d=Vn(f);if(typeof d!="undefined"&&(f.classList.contains("annotate")||Q("content.code.annotate"))){let g=Tr(d,e,t);l.push(Le(f).pipe(W(i),m(({width:L,height:ee})=>L&&ee),Y(),b(L=>L?g:x)))}}let u=M(":scope > span[id]",e);if(u.length&&(e.classList.add("md-code__content"),e.closest(".select")||Q("content.code.select")&&!e.closest(".no-select"))){let d=+u[0].id.split("-").pop(),g=Hn();s.push(g),Q("content.tooltips")&&l.push(Je(g,{viewport$}));let L=h(g,"click").pipe(Ut(R=>!R,!1),T(()=>g.blur()),le());L.subscribe(R=>{g.classList.toggle("md-code__button--active",R)});let ee=fe(u).pipe(J(R=>nt(R).pipe(m(se=>[R,se]))));L.pipe(b(R=>R?ee:x)).subscribe(([R,se])=>{let ce=ue(".hll.select",R);if(ce&&!se)ce.replaceWith(...Array.from(ce.childNodes));else if(!ce&&se){let he=document.createElement("span");he.className="hll select",he.append(...Array.from(R.childNodes).slice(1)),R.append(he)}});let ne=fe(u).pipe(J(R=>h(R,"mousedown").pipe(T(se=>se.preventDefault()),m(()=>R)))),Z=L.pipe(b(R=>R?ne:x),te(Dn),m(([R,se])=>{var he;let ce=u.indexOf(R)+d;if(se===!1)return[ce,ce];{let Se=M(".hll",e).map(je=>u.indexOf(je.parentElement)+d);return(he=window.getSelection())==null||he.removeAllRanges(),[Math.min(ce,...Se),Math.max(ce,...Se)]}})),H=Zr(x).pipe(v(R=>R.startsWith(`__codelineno-${p}-`)));H.subscribe(R=>{let[,,se]=R.split("-"),ce=se.split(":").map(Se=>+Se-d+1);ce.length===1&&ce.push(ce[0]);for(let Se of M(".hll:not(.select)",e))Se.replaceWith(...Array.from(Se.childNodes));let he=u.slice(ce[0]-1,ce[1]);for(let Se of he){let je=document.createElement("span");je.className="hll",je.append(...Array.from(Se.childNodes).slice(1)),Se.append(je)}}),H.pipe(Ee(1),xe(pe)).subscribe(R=>{if(R.includes(":")){let se=document.getElementById(R.split(":")[0]);se&&setTimeout(()=>{let ce=se,he=-64;for(;ce!==document.body;)he+=ce.offsetTop,ce=ce.offsetParent;window.scrollTo({top:he})},1)}});let Fe=fe(M('a[href^="#__codelineno"]',f)).pipe(J(R=>h(R,"click").pipe(T(se=>se.preventDefault()),m(()=>R)))).pipe(W(i),te(Dn),m(([R,se])=>{let he=+F(`[id="${R.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(se===!1)return[he,he];{let Se=M(".hll",e).map(je=>+je.parentElement.id.split("-").pop());return[Math.min(he,...Se),Math.max(he,...Se)]}}));O(Z,Fe).subscribe(R=>{let se=`#__codelineno-${p}-`;R[0]===R[1]?se+=R[0]:se+=`${R[0]}:${R[1]}`,history.replaceState({},"",se),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+se,oldURL:window.location.href}))})}if(Nn.default.isSupported()&&(e.closest(".copy")||Q("content.code.copy")&&!e.closest(".no-copy"))){let d=Cn(a.id);s.push(d),Q("content.tooltips")&&l.push(Je(d,{viewport$}))}if(s.length){let d=kn();d.append(...s),a.insertBefore(d,e)}return Ya(e).pipe(T(d=>n.next(d)),A(()=>n.complete()),m(d=>j({ref:e},d)),Ne(O(...l).pipe(W(i))))});return Q("content.lazy")?lt(e).pipe(v(n=>n),Ee(1),b(()=>o)):o}function Ba(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function qn(e,t){return k(()=>{let r=new w;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Ba(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function Ga(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],o=e.nextElementSibling;for(;o&&!(o instanceof HTMLHeadingElement);)r.push(o),o=o.nextElementSibling;return r}function Ja(e,t){for(let r of M("[href], [src]",e))for(let o of["href","src"]){let n=r.getAttribute(o);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){r[o]=new URL(r.getAttribute(o),t).toString();break}}return $(e)}function Kn(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return x;if(!(Q("navigation.instant.preview")||e.hasAttribute("data-preview")))return x;let o=V([Ke(e),nt(e)]).pipe(m(([i,s])=>i||s),Y(),v(i=>i));return bt([r,o]).pipe(b(([i])=>{let s=new URL(e.href);return s.search=s.hash="",i.has(`${s}`)?$(s):x}),b(i=>yr(i).pipe(b(s=>Ja(s,i)))),b(i=>{let s=e.hash?`article [id="${e.hash.slice(1)}"]`:"article h1",a=ue(s,i);return typeof a=="undefined"?x:$(Ga(a))})).pipe(b(i=>{let s=new I(a=>{let c=wr(...i);return a.next(c),document.body.append(c),()=>c.remove()});return Nt(e,j({content$:s},t))}))}var Qn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ao,Za=0;function es(){return typeof mermaid=="undefined"||mermaid instanceof Element?At("https://unpkg.com/mermaid@10/dist/mermaid.min.js"):$(void 0)}function Yn(e){return e.classList.remove("mermaid"),ao||(ao=es().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Qn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),X(1))),ao.subscribe(()=>bo(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Za++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),ao.pipe(m(()=>({ref:e})))}var Bn=S("table");function Gn(e){return e.replaceWith(Bn),Bn.replaceWith(Pn(e)),$({ref:e})}function ts(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>F(`label[for="${r.id}"]`))))).pipe(K(F(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Jn(e,{viewport$:t,target$:r}){let o=F(".tabbed-labels",e),n=M(":scope > input",e),i=oo("prev");e.append(i);let s=oo("next");return e.append(s),k(()=>{let a=new w,c=a.pipe(re(),ae(!0));V([a,Le(e)]).pipe(W(c),$e(1,ge)).subscribe({next([{active:p},l]){let f=Qe(p),{width:u}=de(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=gr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),V([Ye(o),Le(o)]).pipe(W(c)).subscribe(([p,l])=>{let f=Ct(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(W(c)).subscribe(p=>{let{width:l}=de(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(W(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=F(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return Q("content.tabs.link")&&a.pipe(Pe(1),te(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let g of M("[data-tabs]"))for(let L of M(":scope > input",g)){let ee=F(`label[for="${L.id}"]`);if(ee!==p&&ee.innerText.trim()===f){ee.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(W(c)).subscribe(()=>{for(let p of M("audio, video",e))p.pause()}),lt(e).pipe(b(()=>ts(n)),T(p=>a.next(p)),A(()=>a.complete()),m(p=>j({ref:e},p)))}).pipe(Ze(pe))}function Xn(e,t){let{viewport$:r,target$:o,print$:n}=t;return O(...M(".annotate:not(.highlight)",e).map(i=>Wn(i,{target$:o,print$:n})),...M("pre:not(.mermaid) > code",e).map(i=>zn(i,{target$:o,print$:n})),...M("a:not([title])",e).map(i=>Kn(i,t)),...M("pre.mermaid",e).map(i=>Yn(i)),...M("table:not([class])",e).map(i=>Gn(i)),...M("details",e).map(i=>qn(i,{target$:o,print$:n})),...M("[data-tabs]",e).map(i=>Jn(i,{viewport$:r,target$:o})),...M("[title]",e).filter(()=>Q("content.tooltips")).map(i=>Je(i,{viewport$:r})),...M(".footnote-ref",e).filter(()=>Q("content.footnote.tooltips")).map(i=>Nt(i,{content$:new I(s=>{let a=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(a).cloneNode(!0).children),p=wr(...c);return s.next(p),document.body.append(p),()=>p.remove()}),viewport$:r})))}function rs(e,{alert$:t}){return t.pipe(b(r=>O($(!0),$(!1).pipe(ot(2e3))).pipe(m(o=>({message:r,active:o})))))}function Zn(e,t){let r=F(".md-typeset",e);return k(()=>{let o=new w;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),rs(e,t).pipe(T(n=>o.next(n)),A(()=>o.complete()),m(n=>j({ref:e},n)))})}var os=0;function ns(e,t){document.body.append(e);let{width:r}=de(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=vr(t),n=typeof o!="undefined"?Ye(o):$({x:0,y:0}),i=O(Ke(t),nt(t)).pipe(Y());return V([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Qe(t),l=de(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function ei(e){let t=e.title;if(!t.length)return x;let r=`__tooltip_${os++}`,o=Dt(r,"inline"),n=F(".md-typeset",o);return n.innerHTML=t,k(()=>{let i=new w;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(v(({active:s})=>s)),i.pipe(Ae(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe($e(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(gt(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),ns(o,e).pipe(T(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))}).pipe(Ze(pe))}function is({viewport$:e}){if(!Q("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:n}})=>n),tt(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),Y()),o=Be("search");return V([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),Y(),b(n=>n?r:$(!1)),K(!1))}function ti(e,t){return k(()=>V([Le(e),is(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),Y((r,o)=>r.height===o.height&&r.hidden===o.hidden),X(1))}function ri(e,{header$:t,main$:r}){return k(()=>{let o=new w,n=o.pipe(re(),ae(!0));o.pipe(oe("active"),De(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(M("[title]",e)).pipe(v(()=>Q("content.tooltips")),J(s=>ei(s)));return r.subscribe(o),t.pipe(W(n),m(s=>j({ref:e},s)),Ne(i.pipe(W(n))))})}function as(e,{viewport$:t,header$:r}){return Er(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=de(e);return{active:o>=n}}),oe("active"))}function oi(e,t){return k(()=>{let r=new w;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ue(".md-content h1");return typeof o=="undefined"?x:as(o,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))})}function ni(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),Y()),n=o.pipe(b(()=>Le(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),oe("bottom"))));return V([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),Y((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function ss(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return $(...e).pipe(J(o=>h(o,"change").pipe(m(()=>o))),K(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),X(1))}function ii(e){let t=M("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Wt("(prefers-color-scheme: light)");return k(()=>{let i=new w;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;as.key==="Enter"),te(i,(s,a)=>a)).subscribe(({index:s})=>{s=(s+1)%t.length,t[s].click(),t[s].focus()}),i.pipe(m(()=>{let s=Ce("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(xe(pe)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),ss(t).pipe(W(n.pipe(Pe(1))),vt(),T(s=>i.next(s)),A(()=>i.complete()),m(s=>j({ref:e},s)))})}function ai(e,{progress$:t}){return k(()=>{let r=new w;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}function si(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function cs(e,t){let r=new Map;for(let o of M("url",e)){let n=F("loc",o),i=[si(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let s of M("[rel=alternate]",o)){let a=s.getAttribute("href");a!=null&&i.push(si(new URL(a),t))}}return r}function kt(e){return xn(new URL("sitemap.xml",e)).pipe(m(t=>cs(t,new URL(e))),ye(()=>$(new Map)),le())}function ci({document$:e}){let t=new Map;e.pipe(b(()=>M("link[rel=alternate]")),m(r=>new URL(r.href)),v(r=>!t.has(r.toString())),J(r=>kt(r).pipe(m(o=>[r,o]),ye(()=>x)))).subscribe(([r,o])=>{t.set(r.toString().replace(/\/$/,""),o)}),h(document.body,"click").pipe(v(r=>!r.metaKey&&!r.ctrlKey),b(r=>{if(r.target instanceof Element){let o=r.target.closest("a");if(o&&!o.target){let n=[...t].find(([f])=>o.href.startsWith(`${f}/`));if(typeof n=="undefined")return x;let[i,s]=n,a=we();if(a.href.startsWith(i))return x;let c=Te(),p=a.href.replace(c.base,"");p=`${i}/${p}`;let l=s.has(p.split("#")[0])?new URL(p,c.base):new URL(i);return r.preventDefault(),$(l)}}return x})).subscribe(r=>at(r,!0))}var so=Gt(io());function ps(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function pi({alert$:e}){so.default.isSupported()&&new I(t=>{new so.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ps(F(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>Me("clipboard.copied"))).subscribe(e)}function li(e,t){if(!(e.target instanceof Element))return x;let r=e.target.closest("a");if(r===null)return x;if(r.target||e.metaKey||e.ctrlKey)return x;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),$(r)):x}function mi(e){let t=new Map;for(let r of M(":scope > *",e.head))t.set(r.outerHTML,r);return t}function fi(e){for(let t of M("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return $(e)}function ls(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...Q("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=ue(o),i=ue(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=mi(document);for(let[o,n]of mi(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Ce("container");return qe(M("script",r)).pipe(b(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new I(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),x}),re(),ae(document))}function ui({sitemap$:e,location$:t,viewport$:r,progress$:o}){if(location.protocol==="file:")return x;$(document).subscribe(fi);let n=h(document.body,"click").pipe(De(e),b(([a,c])=>li(a,c)),m(({href:a})=>new URL(a)),le()),i=h(window,"popstate").pipe(m(we),le());n.pipe(te(r)).subscribe(([a,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",a)}),O(n,i).subscribe(t);let s=t.pipe(oe("pathname"),b(a=>yr(a,{progress$:o}).pipe(ye(()=>(at(a,!0),x)))),b(fi),b(ls),le());return O(s.pipe(te(t,(a,c)=>c)),t.pipe(oe("pathname"),b(()=>t),oe("hash")),t.pipe(Y((a,c)=>a.pathname===c.pathname&&a.hash===c.hash),b(()=>n),T(()=>history.back()))).subscribe(a=>{var c,p;history.state!==null||!a.hash?window.scrollTo(0,(p=(c=history.state)==null?void 0:c.y)!=null?p:0):(history.scrollRestoration="auto",bn(a.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(oe("offset"),Ae(100)).subscribe(({offset:a})=>{history.replaceState(a,"")}),Q("navigation.instant.prefetch")&&O(h(document.body,"mousemove"),h(document.body,"focusin")).pipe(De(e),b(([a,c])=>li(a,c)),Ae(25),Qr(({href:a})=>a),hr(a=>{let c=document.createElement("link");return c.rel="prefetch",c.href=a.toString(),document.head.appendChild(c),h(c,"load").pipe(m(()=>c),Ee(1))})).subscribe(a=>a.remove()),s}var bi=Gt(hi());function vi(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,bi.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function zt(e){return e.type===1}function Sr(e){return e.type===3}function gi(e,t){let r=On(e);return O($(location.protocol!=="file:"),Be("search")).pipe(Re(o=>o),b(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:Q("search.suggest")}}})),r}function xi({document$:e}){let t=Te(),r=Ge(new URL("../versions.json",t.base)).pipe(ye(()=>x)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),b(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),te(o),b(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?x:(i.preventDefault(),$(c))}}return x}),b(i=>kt(new URL(i)).pipe(m(s=>{let c=we().href.replace(t.base,i);return s.has(c.split("#")[0])?new URL(c):new URL(i)})))))).subscribe(n=>at(n,!0)),V([r,o]).subscribe(([n,i])=>{F(".md-header__topic").appendChild(In(n,i))}),e.pipe(b(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of me("outdated"))a.hidden=!1})}function hs(e,{worker$:t}){let{searchParams:r}=we();r.has("q")&&(it("search",!0),e.value=r.get("q"),e.focus(),Be("search").pipe(Re(i=>!i)).subscribe(()=>{let i=we();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=Ke(e),n=O(t.pipe(Re(zt)),h(e,"keyup"),o).pipe(m(()=>e.value),Y());return V([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),X(1))}function yi(e,{worker$:t}){let r=new w,o=r.pipe(re(),ae(!0));V([t.pipe(Re(zt)),r],(i,s)=>s).pipe(oe("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(oe("focus")).subscribe(({focus:i})=>{i&&it("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=F("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),hs(e,{worker$:t}).pipe(T(i=>r.next(i)),A(()=>r.complete()),m(i=>j({ref:e},i)),X(1))}function Ei(e,{worker$:t,query$:r}){let o=new w,n=mn(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=F(":scope > :first-child",e),a=F(":scope > :last-child",e);Be("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(te(r),Gr(t.pipe(Re(zt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?Me("search.result.none"):Me("search.result.placeholder");break;case 1:s.textContent=Me("search.result.one");break;default:let u=br(l.length);s.textContent=Me("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),b(({items:l})=>O($(...l.slice(0,10)),$(...l.slice(10)).pipe(tt(4),Xr(n),b(([f])=>f)))),m($n),le());return c.subscribe(l=>a.appendChild(l)),c.pipe(J(l=>{let f=ue("details",l);return typeof f=="undefined"?x:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(Sr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),A(()=>o.complete()),m(l=>j({ref:e},l)))}function bs(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=we();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function wi(e,t){let r=new w,o=r.pipe(re(),ae(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),bs(e,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>j({ref:e},n)))}function Ti(e,{worker$:t,keyboard$:r}){let o=new w,n=Ce("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(xe(pe),m(()=>n.value),Y());return o.pipe(De(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(Sr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Si(e,{index$:t,keyboard$:r}){let o=Te();try{let n=gi(o.search,t),i=Ce("search-query",e),s=Ce("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>it("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ve();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of M(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":it("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...M(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ve()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=yi(i,{worker$:n});return O(a,Ei(s,{worker$:n,query$:a})).pipe(Ne(...me("search-share",e).map(c=>wi(c,{query$:a})),...me("search-suggest",e).map(c=>Ti(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,et}}function Oi(e,{index$:t,location$:r}){return V([t,r.pipe(K(we()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>vi(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function vs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return V([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),Y((i,s)=>i.height===s.height&&i.locked===s.locked))}function co(e,o){var n=o,{header$:t}=n,r=ho(n,["header$"]);let i=F(".md-sidebar__scrollwrap",e),{y:s}=Qe(i);return k(()=>{let a=new w,c=a.pipe(re(),ae(!0)),p=a.pipe($e(0,ge));return p.pipe(te(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Re()).subscribe(()=>{for(let l of M(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2})}}}),fe(M("label[tabindex]",e)).pipe(J(l=>h(l,"click").pipe(xe(pe),m(()=>l),W(c)))).subscribe(l=>{let f=F(`[id="${l.htmlFor}"]`);F(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),Q("content.tooltips")&&fe(M("abbr[title]",e)).pipe(J(l=>Je(l,{viewport$})),W(c)).subscribe(),vs(e,r).pipe(T(l=>a.next(l)),A(()=>a.complete()),m(l=>j({ref:e},l)))})}function Li(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return bt(Ge(`${r}/releases/latest`).pipe(ye(()=>x),m(o=>({version:o.tag_name})),rt({})),Ge(r).pipe(ye(()=>x),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),rt({}))).pipe(m(([o,n])=>j(j({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(m(o=>({repositories:o.public_repos})),rt({}))}}function Mi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(ye(()=>x),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),rt({}))}function _i(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return Li(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return Mi(r,o)}return x}var gs;function xs(e){return gs||(gs=k(()=>{let t=__md_get("__source",sessionStorage);if(t)return $(t);if(me("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return x}return _i(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(ye(()=>x),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function Ai(e){let t=F(":scope > :last-child",e);return k(()=>{let r=new w;return r.subscribe(({facts:o})=>{t.appendChild(Rn(o)),t.classList.add("md-source__repository--active")}),xs(e).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function ys(e,{viewport$:t,header$:r}){return Le(document.body).pipe(b(()=>Er(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),oe("hidden"))}function Ci(e,t){return k(()=>{let r=new w;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(Q("navigation.tabs.sticky")?$({hidden:!1}):ys(e,t)).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>j({ref:e},o)))})}function Es(e,{viewport$:t,header$:r}){let o=new Map,n=M(".md-nav__link",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ue(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(oe("height"),m(({height:a})=>{let c=Ce("main"),p=F(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),le());return Le(document.body).pipe(oe("height"),b(a=>k(()=>{let c=[];return $([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),De(i),b(([c,p])=>t.pipe(Ut(([l,f],{offset:{y:u},size:d})=>{let g=u+d.height>=Math.floor(a.height);for(;f.length;){let[,L]=f[0];if(L-p=u&&!g)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),Y((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),K({prev:[],next:[]}),tt(2,1),m(([a,c])=>a.prev.length{let i=new w,s=i.pipe(re(),ae(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),Q("toc.follow")){let a=O(t.pipe(Ae(1),m(()=>{})),t.pipe(Ae(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),De(o.pipe(xe(pe))),te(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=vr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=de(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return Q("navigation.tracking")&&t.pipe(W(s),oe("offset"),Ae(250),Pe(1),W(n.pipe(Pe(1))),vt({delay:250}),te(i)).subscribe(([,{prev:a}])=>{let c=we(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Es(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))})}function ws(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),tt(2,1),m(([s,a])=>s>a&&a>0),Y()),i=r.pipe(m(({active:s})=>s));return V([i,n]).pipe(m(([s,a])=>!(s&&a)),Y(),W(o.pipe(Pe(1))),ae(!0),vt({delay:250}),m(s=>({hidden:s})))}function ki(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new w,s=i.pipe(re(),ae(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(s),oe("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),ws(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>j({ref:e},a)))}function $i({document$:e,viewport$:t}){e.pipe(b(()=>M(".md-ellipsis")),J(r=>lt(r).pipe(W(e.pipe(Pe(1))),v(o=>o),m(()=>r),Ee(1))),v(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,Je(n,{viewport$:t}).pipe(W(e.pipe(Pe(1))),A(()=>n.removeAttribute("title")))})).subscribe(),e.pipe(b(()=>M(".md-status")),J(r=>Je(r,{viewport$:t}))).subscribe()}function Ri({document$:e,tablet$:t}){e.pipe(b(()=>M(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),J(r=>h(r,"change").pipe(Jr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),te(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ts(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Pi({document$:e}){e.pipe(b(()=>M("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ts),J(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ii({viewport$:e,tablet$:t}){V([Be("search"),t]).pipe(m(([r,o])=>r&&!o),b(r=>$(r).pipe(ot(r?400:100))),te(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ss(){return location.protocol==="file:"?At(`${new URL("search/search_index.js",Or.base)}`).pipe(m(()=>__index),X(1)):Ge(new URL("search/search_index.json",Or.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var st=on(),Kt=dn(),$t=vn(Kt),po=un(),He=Sn(),Lr=Wt("(min-width: 960px)"),ji=Wt("(min-width: 1220px)"),Ui=gn(),Or=Te(),Wi=document.forms.namedItem("search")?Ss():et,lo=new w;pi({alert$:lo});ci({document$:st});var mo=new w,Di=kt(Or.base);Q("navigation.instant")&&ui({sitemap$:Di,location$:Kt,viewport$:He,progress$:mo}).subscribe(st);var Fi;((Fi=Or.version)==null?void 0:Fi.provider)==="mike"&&xi({document$:st});O(Kt,$t).pipe(ot(125)).subscribe(()=>{it("drawer",!1),it("search",!1)});po.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ue("link[rel=prev]");typeof t!="undefined"&&at(t);break;case"n":case".":let r=ue("link[rel=next]");typeof r!="undefined"&&at(r);break;case"Enter":let o=Ve();o instanceof HTMLLabelElement&&o.click()}});$i({viewport$:He,document$:st});Ri({document$:st,tablet$:Lr});Pi({document$:st});Ii({viewport$:He,tablet$:Lr});var mt=ti(Ce("header"),{viewport$:He}),qt=st.pipe(m(()=>Ce("main")),b(e=>ni(e,{viewport$:He,header$:mt})),X(1)),Os=O(...me("consent").map(e=>Mn(e,{target$:$t})),...me("dialog").map(e=>Zn(e,{alert$:lo})),...me("header").map(e=>ri(e,{viewport$:He,header$:mt,main$:qt})),...me("palette").map(e=>ii(e)),...me("progress").map(e=>ai(e,{progress$:mo})),...me("search").map(e=>Si(e,{index$:Wi,keyboard$:po})),...me("source").map(e=>Ai(e))),Ls=k(()=>O(...me("announce").map(e=>Ln(e)),...me("content").map(e=>Xn(e,{sitemap$:Di,viewport$:He,target$:$t,print$:Ui})),...me("content").map(e=>Q("search.highlight")?Oi(e,{index$:Wi,location$:Kt}):x),...me("header-title").map(e=>oi(e,{viewport$:He,header$:mt})),...me("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?eo(ji,()=>co(e,{viewport$:He,header$:mt,main$:qt})):eo(Lr,()=>co(e,{viewport$:He,header$:mt,main$:qt}))),...me("tabs").map(e=>Ci(e,{viewport$:He,header$:mt})),...me("toc").map(e=>Hi(e,{viewport$:He,header$:mt,main$:qt,target$:$t})),...me("top").map(e=>ki(e,{viewport$:He,header$:mt,main$:qt,target$:$t})))),Ni=st.pipe(b(()=>Ls),Ne(Os),X(1));Ni.subscribe();window.document$=st;window.location$=Kt;window.target$=$t;window.keyboard$=po;window.viewport$=He;window.tablet$=Lr;window.screen$=ji;window.print$=Ui;window.alert$=lo;window.progress$=mo;window.component$=Ni;})(); diff --git a/latest/assets/stylesheets/main.d5b5f0fd.min.css b/latest/assets/stylesheets/main.46e89654.min.css similarity index 79% rename from latest/assets/stylesheets/main.d5b5f0fd.min.css rename to latest/assets/stylesheets/main.46e89654.min.css index 17f5e1789..621427735 100644 --- a/latest/assets/stylesheets/main.d5b5f0fd.min.css +++ b/latest/assets/stylesheets/main.46e89654.min.css @@ -1 +1 @@ -@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:1fr;opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:1fr;opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:#0000008a;cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem #0000;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:#00000042;border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:#ffffff1f}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem #00000012;color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:#0000;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::placeholder{transition:color .25s}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:#0000}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{-webkit-backface-visibility:hidden;backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:block}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:1fr;opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:1fr;opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:#0000008a;cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.984375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.234375em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem #0000;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:#00000042;border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:#ffffff1f}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem #00000012;color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:#0000;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::placeholder{transition:color .25s}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.984375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:#0000}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.984375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>.md-icon{margin-left:.2rem}[dir=rtl] .md-search__options>.md-icon{margin-right:.2rem}.md-search__options>.md-icon{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>.md-icon:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>.md-icon:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.984375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more>summary{cursor:pointer;display:block;outline:none;position:sticky;scroll-snap-align:start;top:0;z-index:1}.md-search-result__more>summary::marker{display:none}.md-search-result__more>summary::-webkit-details-marker{display:none}.md-search-result__more>summary>div{color:var(--md-typeset-a-color);font-size:.64rem;padding:.75em .8rem;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more>summary>div{padding-left:2.2rem}[dir=rtl] .md-search-result__more>summary>div{padding-right:2.2rem}}.md-search-result__more>summary:focus>div,.md-search-result__more>summary:hover>div{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more[open]>summary{background-color:var(--md-default-bg-color)}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.984375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result .md-typeset{color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.6}.md-search-result .md-typeset h1{color:var(--md-default-fg-color);font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result .md-typeset h1 mark{text-decoration:none}.md-search-result .md-typeset h2{color:var(--md-default-fg-color);font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result .md-typeset h2 mark{text-decoration:none}.md-search-result__terms{color:var(--md-default-fg-color);display:block;font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color);text-decoration:underline}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:xxx;list-style:none}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(xxx);counter-increment:xxx;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{-webkit-backface-visibility:hidden;backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/latest/built-in-features/aws-ec2-connect/index.html b/latest/built-in-features/aws-ec2-connect/index.html index bb468f9bf..637004d3c 100644 --- a/latest/built-in-features/aws-ec2-connect/index.html +++ b/latest/built-in-features/aws-ec2-connect/index.html @@ -1,4 +1,4 @@ - Configure AWS EC2 Connect - Leapp - Docs

EC2 connect through AWS SSM

What is AWS EC2 Connect

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

How To configure AWS EC2 Connect in Leapp

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS
example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.

Video tutorial

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

\ No newline at end of file +

EC2 connect through AWS SSM

What is AWS EC2 Connect

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

How To configure AWS EC2 Connect in Leapp

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS
example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.

Video tutorial

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

\ No newline at end of file diff --git a/latest/built-in-features/aws-named-profiles/index.html b/latest/built-in-features/aws-named-profiles/index.html index 93d52ecf4..374aaa076 100644 --- a/latest/built-in-features/aws-named-profiles/index.html +++ b/latest/built-in-features/aws-named-profiles/index.html @@ -1,4 +1,4 @@ - Configure Named Profiles - Leapp - Docs

AWS Multi-profile management

What is a Named Profile

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

How to configure a Named Profile in Leapp

Named Profiles can be created in 3 ways:

Click on the gear icon Screenshot 2022-02-03 at 15 22 34 and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.


Screenshot 2022-02-03 at 15 25 43

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the "Change Profile" option in the session list.

Named Profile List

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the Screenshot 2022-02-03 at 15 32 11 button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

\ No newline at end of file +

AWS Multi-profile management

What is a Named Profile

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

How to configure a Named Profile in Leapp

Named Profiles can be created in 3 ways:

Click on the gear icon Screenshot 2022-02-03 at 15 22 34 and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.


Screenshot 2022-02-03 at 15 25 43

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the "Change Profile" option in the session list.

Named Profile List

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the Screenshot 2022-02-03 at 15 32 11 button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

\ No newline at end of file diff --git a/latest/built-in-features/general-options/index.html b/latest/built-in-features/general-options/index.html index 46c0a8448..cabd690ae 100644 --- a/latest/built-in-features/general-options/index.html +++ b/latest/built-in-features/general-options/index.html @@ -1 +1 @@ - General Options - Leapp - Docs

General Options

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

Default Regions

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

Terminal Selection

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

Color Theme

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

Default Webconsole Duration

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

\ No newline at end of file + General Options - Leapp - Docs

General Options

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

Default Regions

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

Terminal Selection

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

Color Theme

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

Default Webconsole Duration

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

\ No newline at end of file diff --git a/latest/built-in-features/multi-console/index.html b/latest/built-in-features/multi-console/index.html index 2fabecc04..2d2be964c 100644 --- a/latest/built-in-features/multi-console/index.html +++ b/latest/built-in-features/multi-console/index.html @@ -1,4 +1,4 @@ - Configure Multi Console - Leapp - Docs

Multi-Console Browser Extension

What is Multi Console

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

List of Supported Browsers

Browser Supported
Firefox ✅
Chrome ✅
Edge ✅
Brave ✅
Safari ❌

How to Configure Multi Console in Leapp

Install the Extension

Firefox

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox ⇩

Chrome, Edge and other Chromium based browsers

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others ⇩

Uninstall the Extension

Firefox

  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove

Chrome, Edge and other Chromium based browsers

  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select "Cookies". Then, remove all cookies by clicking "Remove" until the cookie list is empty and finally click on Done

uninstall extension step 1 uninstall extension step 2

How to use it

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option
enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).


By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui
leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

\ No newline at end of file +

Multi-Console Browser Extension

What is Multi Console

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

List of Supported Browsers

Browser Supported
Firefox ✅
Chrome ✅
Edge ✅
Brave ✅
Safari ❌

How to Configure Multi Console in Leapp

Install the Extension

Firefox

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox ⇩

Chrome, Edge and other Chromium based browsers

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others ⇩

Uninstall the Extension

Firefox

  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove

Chrome, Edge and other Chromium based browsers

  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select "Cookies". Then, remove all cookies by clicking "Remove" until the cookie list is empty and finally click on Done

uninstall extension step 1 uninstall extension step 2

How to use it

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option
enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).


By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui
leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

\ No newline at end of file diff --git a/latest/built-in-features/opening-web-console/index.html b/latest/built-in-features/opening-web-console/index.html index 3ce5dcb82..830861413 100644 --- a/latest/built-in-features/opening-web-console/index.html +++ b/latest/built-in-features/opening-web-console/index.html @@ -1,4 +1,4 @@ - Configure Open Web Console - Leapp - Docs

Opening AWS Web Console

What is Open Web Console

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

How to Configure Open Web Console in Leapp

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

\ No newline at end of file +

Opening AWS Web Console

What is Open Web Console

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

How to Configure Open Web Console in Leapp

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

\ No newline at end of file diff --git a/latest/cli/index.html b/latest/cli/index.html index 94f5be6ce..aa695a449 100644 --- a/latest/cli/index.html +++ b/latest/cli/index.html @@ -1,4 +1,4 @@ - Index - Leapp - Docs

Index

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli
+ Index - Leapp - Docs      

Index

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli
 $ leapp COMMAND
 running command...
 $ leapp (--version)
@@ -7,4 +7,4 @@
 USAGE
   $ leapp COMMAND
 ...
-

Command Topics

\ No newline at end of file +

Command Topics

\ No newline at end of file diff --git a/latest/cli/scopes/help/index.html b/latest/cli/scopes/help/index.html index 440266ebc..b64baca9d 100644 --- a/latest/cli/scopes/help/index.html +++ b/latest/cli/scopes/help/index.html @@ -1,4 +1,4 @@ - Help - Leapp - Docs

leapp help

Display help for leapp.

leapp help [COMMANDS]

Display help for leapp.

USAGE
+ Help - Leapp - Docs      

leapp help

Display help for leapp.

leapp help [COMMANDS]

Display help for leapp.

USAGE
   $ leapp help [COMMANDS] [-n]
 
 ARGUMENTS
@@ -9,4 +9,4 @@
 
 DESCRIPTION
   Display help for leapp.
-

See code: @oclif/plugin-help

\ No newline at end of file +

See code: @oclif/plugin-help

\ No newline at end of file diff --git a/latest/cli/scopes/idp-url/index.html b/latest/cli/scopes/idp-url/index.html index f9b6d905b..7e1a234fb 100644 --- a/latest/cli/scopes/idp-url/index.html +++ b/latest/cli/scopes/idp-url/index.html @@ -1,4 +1,4 @@ - Idp Url - Leapp - Docs

leapp idp-url

SAML 2.0 Identity providers URL management

leapp idp-url create

Create a new identity provider URL

USAGE
+ Idp Url - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/integration/index.html b/latest/cli/scopes/integration/index.html index 6eac1dee2..c281727b5 100644 --- a/latest/cli/scopes/integration/index.html +++ b/latest/cli/scopes/integration/index.html @@ -1,4 +1,4 @@ - Integration - Leapp - Docs

leapp integration

Leapp Integrations management

leapp integration create

Create a new integration

USAGE
+ Integration - Leapp - Docs      

leapp integration

Leapp Integrations management

leapp integration create

Create a new integration

USAGE
   $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]
     [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]
 
@@ -92,4 +92,4 @@
   $leapp integration sync
 
   $leapp integration sync --integrationId ID
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/profile/index.html b/latest/cli/scopes/profile/index.html index c8faa183e..87a7f2c3f 100644 --- a/latest/cli/scopes/profile/index.html +++ b/latest/cli/scopes/profile/index.html @@ -1,4 +1,4 @@ - Profile - Leapp - Docs

leapp profile

Leapp AWS Multi-profile management

leapp profile create

Create a new AWS named profile

USAGE
+ Profile - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/region/index.html b/latest/cli/scopes/region/index.html index 23483d039..168c1e75c 100644 --- a/latest/cli/scopes/region/index.html +++ b/latest/cli/scopes/region/index.html @@ -1,4 +1,4 @@ - Region - Leapp - Docs

leapp region

Leapp regions management

leapp region get-default

Displays the default region

USAGE
+ Region - Leapp - Docs      

leapp region

Leapp regions management

leapp region get-default

Displays the default region

USAGE
   $ leapp region get-default
 
 DESCRIPTION
@@ -19,4 +19,4 @@
   $leapp region set-default
 
   $leapp region set-default --region AWSREGION
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/session/index.html b/latest/cli/scopes/session/index.html index c9c73b93d..d0341329b 100644 --- a/latest/cli/scopes/session/index.html +++ b/latest/cli/scopes/session/index.html @@ -1,4 +1,4 @@ - Session - Leapp - Docs

leapp session

Sessions management

leapp session add

Add a new session

USAGE
+ Session - Leapp - Docs      

leapp session

Sessions management

leapp session add

Add a new session

USAGE
   $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]
     [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]
     [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType
@@ -242,4 +242,4 @@
   $leapp session stop SESSIONNAME --noInteractive
 
   $leapp session stop --sessionId SESSIONID
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/set-workspace/index.html b/latest/cli/scopes/set-workspace/index.html index 6f006e375..d86b2055b 100644 --- a/latest/cli/scopes/set-workspace/index.html +++ b/latest/cli/scopes/set-workspace/index.html @@ -1,4 +1,4 @@ - Set Workspace - Leapp - Docs

leapp set-workspace

Set the current Leapp workspace

leapp set-workspace [WORKSPACENAME]

Set the current Leapp workspace

USAGE
+ Set Workspace - Leapp - Docs      

leapp set-workspace

Set the current Leapp workspace

leapp set-workspace [WORKSPACENAME]

Set the current Leapp workspace

USAGE
   $ leapp set-workspace [WORKSPACENAME]
 
 ARGUMENTS
@@ -13,4 +13,4 @@
   $leapp team set-workspace local
 
   $leapp team set-workspace WORKSPACE-NAME
-

See code: dist/commands/set-workspace.ts

\ No newline at end of file +

See code: dist/commands/set-workspace.ts

\ No newline at end of file diff --git a/latest/cli/scopes/team/index.html b/latest/cli/scopes/team/index.html index 8b8cc4ff5..ca1192a4e 100644 --- a/latest/cli/scopes/team/index.html +++ b/latest/cli/scopes/team/index.html @@ -1,4 +1,4 @@ - Team - Leapp - Docs

leapp team

Login to your Team account

leapp team login

Login to your Team account

USAGE
+ Team - Leapp - Docs      
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/cli/scopes/version/index.html b/latest/cli/scopes/version/index.html index 641f0998d..2dc74b750 100644 --- a/latest/cli/scopes/version/index.html +++ b/latest/cli/scopes/version/index.html @@ -1,4 +1,4 @@ - Version - Leapp - Docs

leapp version

Displays the Cli and Core versions

leapp version

Displays the Cli and Core versions

USAGE
+ Version - Leapp - Docs      

leapp version

Displays the Cli and Core versions

leapp version

Displays the Cli and Core versions

USAGE
   $ leapp version
 
 DESCRIPTION
@@ -6,4 +6,4 @@
 
 EXAMPLES
   $leapp version
-

See code: dist/commands/version.ts

\ No newline at end of file +

See code: dist/commands/version.ts

\ No newline at end of file diff --git a/latest/cli/scopes/workspace/index.html b/latest/cli/scopes/workspace/index.html index ada1474b9..f223628ef 100644 --- a/latest/cli/scopes/workspace/index.html +++ b/latest/cli/scopes/workspace/index.html @@ -1,4 +1,4 @@ - Workspace - Leapp - Docs

leapp workspace

Show the current workspace

leapp workspace

Show the current workspace

USAGE
+ Workspace - Leapp - Docs      

leapp workspace

Show the current workspace

leapp workspace

Show the current workspace

USAGE
   $ leapp workspace
 
 DESCRIPTION
@@ -6,4 +6,4 @@
 
 EXAMPLES
   $leapp workspace
-

See code: dist/commands/workspace.ts

\ No newline at end of file +

See code: dist/commands/workspace.ts

\ No newline at end of file diff --git a/latest/configuration/index.html b/latest/configuration/index.html index f4a684058..4ba77e158 100644 --- a/latest/configuration/index.html +++ b/latest/configuration/index.html @@ -1 +1 @@ - Add your first configuration - Leapp - Docs
\ No newline at end of file + Add your first configuration - Leapp - Docs
\ No newline at end of file diff --git a/latest/configuring-integration/configure-aws-single-sign-on-integration/index.html b/latest/configuring-integration/configure-aws-single-sign-on-integration/index.html index 5d8a3a04a..f37a2bc32 100644 --- a/latest/configuring-integration/configure-aws-single-sign-on-integration/index.html +++ b/latest/configuring-integration/configure-aws-single-sign-on-integration/index.html @@ -1 +1 @@ - Configure an AWS Identity Center (ex AWS Single Sign-On) integration - Leapp - Docs

Configure AWS Single Sign-On integration

What is AWS Identity Center (ex AWS Single Sign-On)

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as AWS Single Sign-on
AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start.
REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part.

Video tutorial

\ No newline at end of file + Configure an AWS Identity Center (ex AWS Single Sign-On) integration - Leapp - Docs

Configure AWS Single Sign-On integration

What is AWS Identity Center (ex AWS Single Sign-On)

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as AWS Single Sign-on
AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start.
REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part.

Video tutorial

\ No newline at end of file diff --git a/latest/configuring-integration/configure-azure-integration/index.html b/latest/configuring-integration/configure-azure-integration/index.html index e318ad584..ceb645783 100644 --- a/latest/configuring-integration/configure-azure-integration/index.html +++ b/latest/configuring-integration/configure-azure-integration/index.html @@ -1 +1 @@ - Configure an Azure integration - Leapp - Docs

Configure Azure integration

What is an Azure integration

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

How to configure an Azure integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as Azure
ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database.
LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options.

Video tutorial

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

\ No newline at end of file + Configure an Azure integration - Leapp - Docs

Configure Azure integration

What is an Azure integration

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

How to configure an Azure integration in Leapp

  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.

Required information

Field Description
INTEGRATION TYPE Set as Azure
ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database.
LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options.

Video tutorial

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

\ No newline at end of file diff --git a/latest/configuring-session/configure-aws-iam-role-chained/index.html b/latest/configuring-session/configure-aws-iam-role-chained/index.html index 40d5225ec..500404c18 100644 --- a/latest/configuring-session/configure-aws-iam-role-chained/index.html +++ b/latest/configuring-session/configure-aws-iam-role-chained/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM Role Chained - Leapp - Docs

Configure AWS IAM Role Chained

What is an AWS IAM Role Chained session

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

How to configure an AWS IAM Role Chained in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.
ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity.
ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp.

Video tutorial

\ No newline at end of file +

Configure AWS IAM Role Chained

What is an AWS IAM Role Chained session

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

How to configure an AWS IAM Role Chained in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.
ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity.
ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp.

Video tutorial

\ No newline at end of file diff --git a/latest/configuring-session/configure-aws-iam-role-federated/index.html b/latest/configuring-session/configure-aws-iam-role-federated/index.html index 5e79a8554..5bcd7ffa9 100644 --- a/latest/configuring-session/configure-aws-iam-role-federated/index.html +++ b/latest/configuring-session/configure-aws-iam-role-federated/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM Role Federated - Leapp - Docs

Configure AWS IAM Role Federated

What is an AWS IAM Role Federated session

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.

Supported SAML Identity Providers

Identity Provider AWS Azure
GSUITE ✅ ❌
OKTA ✅ ❌
ONELOGIN ✅ ❌
AZURE AD ✅ ✅
AUTH0 ✅ ❌
KEYCLOAK ✅ ❌
JUMPCLOUD ✅ ❌

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

How to configure an AWS IAM Role Federated in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider.
AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.

Video tutorial

\ No newline at end of file +

Configure AWS IAM Role Federated

What is an AWS IAM Role Federated session

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.

Supported SAML Identity Providers

Identity Provider AWS Azure
GSUITE ✅ ❌
OKTA ✅ ❌
ONELOGIN ✅ ❌
AZURE AD ✅ ✅
AUTH0 ✅ ❌
KEYCLOAK ✅ ❌
JUMPCLOUD ✅ ❌

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

How to configure an AWS IAM Role Federated in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider.
AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers.
ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role.

Video tutorial

\ No newline at end of file diff --git a/latest/configuring-session/configure-aws-iam-user/index.html b/latest/configuring-session/configure-aws-iam-user/index.html index a0e9293fc..360d4cfcb 100644 --- a/latest/configuring-session/configure-aws-iam-user/index.html +++ b/latest/configuring-session/configure-aws-iam-user/index.html @@ -1,4 +1,4 @@ - Configure AWS IAM User - Leapp - Docs

Configure AWS IAM User

What is an AWS IAM User session

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

How to configure an AWS IAM User in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
MFA DEVICE Your MFA device ID to set up multi-factor authentication.
ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
Add AWS IAM User Screen
Add AWS IAM User Screen

Video tutorial

\ No newline at end of file +

Configure AWS IAM User

What is an AWS IAM User session

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

How to configure an AWS IAM User in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.

Required information

Field Description
SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp.
NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name.
REGION Your default region of choice. Select the one which you use the most for this Session.
MFA DEVICE Your MFA device ID to set up multi-factor authentication.
ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone.
Add AWS IAM User Screen
Add AWS IAM User Screen

Video tutorial

\ No newline at end of file diff --git a/latest/configuring-session/configure-localstack/index.html b/latest/configuring-session/configure-localstack/index.html index f86eb9beb..4b713fbe9 100644 --- a/latest/configuring-session/configure-localstack/index.html +++ b/latest/configuring-session/configure-localstack/index.html @@ -1,4 +1,4 @@ - Configure LocalStack - Leapp - Docs

Configure LocalStack

What is a LocalStack session

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

How to configure a LocalStack session in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

\ No newline at end of file +

Configure LocalStack

What is a LocalStack session

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

How to configure a LocalStack session in Leapp

  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

\ No newline at end of file diff --git a/latest/contributing/get-involved/index.html b/latest/contributing/get-involved/index.html index 53d1b6042..6de0360f8 100644 --- a/latest/contributing/get-involved/index.html +++ b/latest/contributing/get-involved/index.html @@ -1 +1 @@ - Get involved - Leapp - Docs

Get involved

Contributions and questions are not just welcome, they’re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you’re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you. 💙

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

\ No newline at end of file + Get involved - Leapp - Docs

Get involved

Contributions and questions are not just welcome, they’re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you’re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you. 💙

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

\ No newline at end of file diff --git a/latest/edit-session/index.html b/latest/edit-session/index.html index 0d4939e36..edd5dd293 100644 --- a/latest/edit-session/index.html +++ b/latest/edit-session/index.html @@ -1 +1 @@ - Editing a session - Leapp - Docs

Editing a session

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can’t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select "edit session". A new modal will appear, allowing the user to choose which parameters to change.

edit session
edit session

Below are the configuration options for every type of session:

Iam User

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault

IAM Role Chained

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing "Create Chained Session"

IAM Role Federated

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

How we handle Secrets when Editing a Session

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

\ No newline at end of file + Editing a session - Leapp - Docs

Editing a session

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can’t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select "edit session". A new modal will appear, allowing the user to choose which parameters to change.

edit session
edit session

Below are the configuration options for every type of session:

Iam User

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault

IAM Role Chained

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing "Create Chained Session"

IAM Role Federated

  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

How we handle Secrets when Editing a Session

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

\ No newline at end of file diff --git a/latest/index.html b/latest/index.html index 02893ca71..f2434dca3 100644 --- a/latest/index.html +++ b/latest/index.html @@ -1 +1 @@ - Overview - Leapp - Docs

Overview

Welcome to Leapp 🚀

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window
Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

Introducing Leapp CLI

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

\ No newline at end of file + Overview - Leapp - Docs

Overview

Welcome to Leapp 🚀

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window
Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

Introducing Leapp CLI

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

\ No newline at end of file diff --git a/latest/installation/install-leapp/index.html b/latest/installation/install-leapp/index.html index 062673f33..9281410a3 100644 --- a/latest/installation/install-leapp/index.html +++ b/latest/installation/install-leapp/index.html @@ -1,5 +1,5 @@ - Install Leapp - Leapp - Docs

Install Leapp

Install Leapp App

MacOS, Windows, and Linux

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp ⇩

Unzip the package and double-click the executable to install.

macOS (Homebrew)

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp
+ Install Leapp - Leapp - Docs      

Install Leapp

Install Leapp App

MacOS, Windows, and Linux

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp ⇩

Unzip the package and double-click the executable to install.

macOS (Homebrew)

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp
 

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

Install Leapp CLI

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli
 

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli
 

Install Leapp CLI on macOS with ARM64 chip (M1, M2)

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64
-

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

\ No newline at end of file +

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

\ No newline at end of file diff --git a/latest/installation/requirements/index.html b/latest/installation/requirements/index.html index b97c0ee68..a77e6d152 100644 --- a/latest/installation/requirements/index.html +++ b/latest/installation/requirements/index.html @@ -1,4 +1,4 @@ - Requirements - Leapp - Docs

Requirements

MacOS and Windows

There are no requirements for macOS and Windows users.

Linux systems

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

sudo pacman -S gnome-keyring
+ Requirements - Leapp - Docs      

Requirements

MacOS and Windows

There are no requirements for macOS and Windows users.

Linux systems

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

sudo pacman -S gnome-keyring
 sudo pacman -S libsecret
 
sudo apt-get install gnome-keyring
 sudo apt-get install libsecret-1-dev
@@ -7,4 +7,4 @@
 

Logging into EC2 Instances via AWS SSM with Leapp

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>
 

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/
 

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/installation/update-leapp/index.html b/latest/installation/update-leapp/index.html index b59e6905e..e7dcc8c38 100644 --- a/latest/installation/update-leapp/index.html +++ b/latest/installation/update-leapp/index.html @@ -1,3 +1,3 @@ - Update Leapp - Leapp - Docs

Update Leapp

Desktop App

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Leapp will close the modal and notify the user that a new update is available by adding a notification dot Screenshot_2021-05-04_at_10 28 21 (1) to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

CLI

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npm update -g @noovolari/leapp-cli
+ Update Leapp - Leapp - Docs      

Update Leapp

Desktop App

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Leapp will close the modal and notify the user that a new update is available by adding a notification dot Screenshot_2021-05-04_at_10 28 21 (1) to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

CLI

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npm update -g @noovolari/leapp-cli
 
brew upgrade Noovolari/brew/leapp-cli
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/integrations/index.html b/latest/integrations/index.html index e3b15d02c..18139332b 100644 --- a/latest/integrations/index.html +++ b/latest/integrations/index.html @@ -1 +1 @@ - Integrations - Leapp - Docs

Integrations

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

Actions

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description
CREATE  Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions.
DELETE  Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.)
SYNC  Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status.
LOGOUT  Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it.

Supported Services

Service Supported
AWS SSO ✅
Okta Coming Soon
OneLogin Coming Soon
AzureAD ✅
\ No newline at end of file + Integrations - Leapp - Docs

Integrations

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

Actions

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description
CREATE  Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions.
DELETE  Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.)
SYNC  Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status.
LOGOUT  Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it.

Supported Services

Service Supported
AWS SSO ✅
Okta Coming Soon
OneLogin Coming Soon
AzureAD ✅
\ No newline at end of file diff --git a/latest/leapp-pro/export-pro-workspace/index.html b/latest/leapp-pro/export-pro-workspace/index.html index befb8fa5d..338b17c78 100644 --- a/latest/leapp-pro/export-pro-workspace/index.html +++ b/latest/leapp-pro/export-pro-workspace/index.html @@ -1,5 +1,5 @@ - Export PRO Workspace - Leapp - Docs

Export PRO Workspace

How to export your Pro Workspace

  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:
    + Export PRO Workspace - Leapp - Docs      

    Export PRO Workspace

    How to export your Pro Workspace

    1. create a backup of your ~/.Leapp/Leapp-lock.json file;
      // From ~/.Leapp directory run the following command:
       cp Leapp-lock.json Leapp-lock.json.bkp
       
    2. log into you Pro Workspace using the Desktop App;

    3. from the Leapp Options "General" tab, click the button next to the "Export Pro/Team workspace" label;

    4. close the Leapp Options dialog;

    5. close Leapp (on macOS ⌘+Q);
    6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
    7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
      rm Leapp-lock.json
       mv Leapp-lock.json.exported Leapp-lock.json
      -
    8. re-open Leapp;
    9. switch to the Local Workspace;
    10. you should now see your Pro Workspace migrated into the Local one.
    \ No newline at end of file +
  2. re-open Leapp;
  3. switch to the Local Workspace;
  4. you should now see your Pro Workspace migrated into the Local one.
\ No newline at end of file diff --git a/latest/leapp-pro/getting-started/index.html b/latest/leapp-pro/getting-started/index.html deleted file mode 100644 index 2fabfc2ac..000000000 --- a/latest/leapp-pro/getting-started/index.html +++ /dev/null @@ -1 +0,0 @@ - Getting Started - Leapp - Docs

Getting Started

Why Leapp Pro?

Leapp Pro enable Users to protect their Cloud access with Username and password.

With Leapp Pro you can back up and synchronize your Leapp workspace and access to any device you want without losing your access configurations.

Getting started guide

Security and syncronization

Once you updgrade your Plan to Leapp Pro, your local Workspace will be moved to the Pro Workspace. All the data inside your workspace are secured with end-to-end encryption through your Master password.

\ No newline at end of file diff --git a/latest/leapp-pro/getting-started/lock/index.html b/latest/leapp-pro/getting-started/lock/index.html deleted file mode 100644 index e6aefcf56..000000000 --- a/latest/leapp-pro/getting-started/lock/index.html +++ /dev/null @@ -1 +0,0 @@ - Lock your Workspace - Leapp - Docs

Lock your Workspace

Leapp Pro allows the user to temporary lock the workspace, making it accessible only by typing again your master-password. This feature provides a further security level on top of the standard Leapp Community edition.

How to lock the Leapp Pro workspace

To lock your Leapp Pro workspace you should click on the Workspace button located in the top-left area and select the Lock option.

Workspace button
Workspace button
Lock option
Lock option

The Leapp Pro lock screen should appear, prompting for your master-password.

Leapp Pro lock screen
Leapp Pro lock screen

Touch ID

You can also use your fingerprint to unlock Leapp if your PC is Touch ID compatible. After Logging to your Pro workspace for the first time, Leapp will associate your workspace with your system Touch ID. After that the option will be available and can also be tweaked in the general tab of the option menu.

Troubles in locking your Workspace

In case of any troubles locking Leapp Pro workspace please contact us.

\ No newline at end of file diff --git a/latest/leapp-pro/getting-started/sign-in/index.html b/latest/leapp-pro/getting-started/sign-in/index.html deleted file mode 100644 index 08506fdf1..000000000 --- a/latest/leapp-pro/getting-started/sign-in/index.html +++ /dev/null @@ -1 +0,0 @@ - Sign-in - Leapp - Docs

Sign-in

With Leapp Pro you can always sign-in from any location, gaining instant access to your personal workspace.

Sign-in to Leapp Pro

After upgrading Leapp Community edition, you can sign-in at any time, just clicking on the Workspace button located in the top-left area and selecting the Sign-in Workspace option.

Workspace button
Workspace button
Sign-in Workspace option
Sign-in Workspace option

The Sign-in Workspace dialog will appear. Enter your Email address, master-password and click on the Add Workspace button.

Sign-in dialog
Sign-in dialog

If the information entered is correct, your Leapp Pro workspace will be displayed and you can immediately use it to manage your cloud credentials.

Leapp Pro Workspace
Leapp Pro Workspace

To avoid unwanted access, you can lock your Leapp Pro workspace at any time.

Troubles in signing in to Leapp Pro?

In case of any troubles signing in to Leapp Pro please contact us.

\ No newline at end of file diff --git a/latest/leapp-pro/getting-started/sign-up/index.html b/latest/leapp-pro/getting-started/sign-up/index.html deleted file mode 100644 index 3bcd13c44..000000000 --- a/latest/leapp-pro/getting-started/sign-up/index.html +++ /dev/null @@ -1 +0,0 @@ - Sign-up - Leapp - Docs

Sign-up

A Leapp Pro upgrade is required to enable new workspace features like Cloud access from multiple locations and Workspace locking.

Sign-up to Leapp Pro

To sign up for Leapp Pro you should upgrade your version of Leapp Community edition. Click on the Options button in the top-right area.

Settings button
Settings button

In the Options dialog, select the Plans tab and click on Upgrade to Pro button.

Plans tab
Plans tab

The upgrade window should appear. Enter your email (it will be the email address associated with your Leapp Pro account) and click on the Upgrade now button.

Upgrade window
Upgrade window

At this point a window will appear, so you can specify a payment method to complete the Leapp Pro upgrade. After the payment process you will receive a confirmation email containing the Complete the registration link.

Upgrade email
Upgrade email

Clicking the link in the confirmation email will open a web page that will allow you to enter your personal info and the master-password, essential to provide the security requirements of Leapp Pro.

Sign-up page
Sign-up page

After entering your personal info and the master-password click the Continue button. You can now finally sign in to Leapp Pro.

Troubles in signing up to Leapp Pro?

In case of any troubles signing up to Leapp Pro please contact us.

How to Sign-in

Take a look to this page to sign-in your Leapp Pro workspace.

\ No newline at end of file diff --git a/latest/leapp-pro/security-and-password/index.html b/latest/leapp-pro/security-and-password/index.html deleted file mode 100644 index a254d61b4..000000000 --- a/latest/leapp-pro/security-and-password/index.html +++ /dev/null @@ -1 +0,0 @@ - Security and password - Leapp - Docs

Password issues

Can I recover my password?

Unfortunately, it is not possible to recover the master password. The master password is very important as it's the key point of our zero-knowledge encryption mechanism. If you forget it, you'll lose access to the previously encrypted Leapp Sessions and Integrations. That's why it is crucial that you keep your password safe; we suggest you to store it in a password manager like 1Password.

How is my data encrypted?

All information associated with your stored data is protected with end-to-end encryption. Leapp Sessions and Integrations are encrypted before being forwarded to the backend. Specifically, Leapp Pro uses AES 256-bit encryption as well as PBKDF-SHA512 to secure your data.

AES is a standard in cryptography and is used by the U.S. government and other government agencies around the world for protecting top-secret data. With proper implementation and a strong encryption key (your Master Password), AES is considered unbreakable.

PBKDF-SHA512 is used to derive the encryption key from your master password. Then this key is salted and hashed for authenticating with the Leapp Pro backend. The default iteration count used with PBKDF2 is 500,000 iterations on the client. Each Secret has its own generated symmetric key; this symmetric key is encrypted using the user’s public RSA key (this is also the foundation of the Secret sharing system). This encryption and decryption are done entirely on the Leapp Pro clients because your master password is never stored on or transmitted to Leapp Team backend.

It is important to highlight the fact that the backend does not act as a credentials broker, i.e. it has no visibility on the long-term/short-term credentials used by Leapp Pro Desktop App/CLI to access the cloud providers. In addition, the secrets retrieved from the backend, are an encrypted version of access configurations; access configurations DO NOT include temporary credentials. There is a single edge case: the IAM User. Indeed, the IAM User Session access configuration contains IAM User’s access keys, which are long-term credentials. Still, the Leapp Pro backend has no visibility on these long-term credentials, as they’re encrypted by the client before being forwarded to the Leapp Team backend.

Touch ID

When you unlock Leapp Pro, using a longer and more secure account password is easier than you might otherwise have chosen.

Your fingerprint is not stored in Leapp.

Leapp never scans or stores your fingerprint. Touch ID is provided by macOS, which only tells Leapp Pro if your fingerprint was recognized or not.

Learn more about Touch ID's advanced security technology.

\ No newline at end of file diff --git a/latest/leapp-pro/synchronization/index.html b/latest/leapp-pro/synchronization/index.html deleted file mode 100644 index fbe1b0356..000000000 --- a/latest/leapp-pro/synchronization/index.html +++ /dev/null @@ -1 +0,0 @@ - Synchronization - Leapp - Docs

Synchronization

What's a Pro Workspace

A Pro Workspace is a new Workspace that is created upon first login with your registered Pro User. This workspace is synchronized with your Cloud account every time you create, edit, or delete an integration or a session; this way it is possible to use Leapp Pro on different devices, maintaining all your saved integrations and sessions.

How the Synchronization works

Synchronization works by encrypting all your sessions and integrations with your master password, created during your sign-up process. This way we maintain a 0-knowlegde approach on your data through all the lifecycle of your Pro workspace.

The encrypted data is then saved in the Cloud on your Leapp Pro personal space.

You, as a Leapp Pro user, can always keep an eye on the status of synchronization using the synchronization widget in the bottom-left area of Leapp.

Synchronization widget - synchronization active and done
Synchronization widget - synchronization active and done

When all the data is correctly synchronized you'll see the image above.

When Leapp Pro is synchronizing you'll see the icon and text changing to the one in the image below.

Synchronization widget - synchronization in progress
Synchronization widget - synchronization in progress

If you eventually lose connection or have a problem in synchronizing your data the widget will turn yellow as shown below.

Synchronization widget - synchronization failed
Synchronization widget - synchronization failed

You have the possibility to manually trigger another synchronization process and see if the problem is resolved.

Info

When Leapp Pro is restarted it will try to synchronize your data in the Cloud if you're logged in, so you can also close Leapp safely even if in synch failed state.

Do you have any trouble with Synchronization

In case of any troubles locking Leapp Pro workspace please contact us.

\ No newline at end of file diff --git a/latest/plugins/plugins-development/index.html b/latest/plugins/plugins-development/index.html index 24b463535..b5b8b98be 100644 --- a/latest/plugins/plugins-development/index.html +++ b/latest/plugins/plugins-development/index.html @@ -1,4 +1,4 @@ - Developer Reference - Leapp - Docs

Developer Reference

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

PluginEnvironment

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

log

  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description
message string the message to show
level LogLevel severity of the message
display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files

fetch

  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description
url string a valid HTTP URL to fetch from

openExternalUrl

  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description
url string a valid HTTP URL to open in the default browser

createSession

  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description
createSessionData SessionData the metadata used to create the Leapp Session

cloneSession

  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
session Session the Leapp Session that I want to clone

updateSession

  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
updateSessionData SessionData the metadata used to update the given Leapp Session
session Session the Leapp Session that I want to update

openTerminal

  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description
command string the command that I want to execute in the platform-specific terminal
env any optional key/value env variables object

getProfileIdByName

  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description
profileName string a valid named profile

getIdpUrlIdByUrl

  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description
url string the URL associated with the IdpUrl I want to retrieve

Example: display a toast message in Leapp

this.pluginEnvironment.log("Hello World", LogLevel.info, true);
+ Developer Reference - Leapp - Docs      

Developer Reference

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

PluginEnvironment

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

log

  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description
message string the message to show
level LogLevel severity of the message
display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files

fetch

  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description
url string a valid HTTP URL to fetch from

openExternalUrl

  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description
url string a valid HTTP URL to open in the default browser

createSession

  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description
createSessionData SessionData the metadata used to create the Leapp Session

cloneSession

  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
session Session the Leapp Session that I want to clone

updateSession

  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description
updateSessionData SessionData the metadata used to update the given Leapp Session
session Session the Leapp Session that I want to update

openTerminal

  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description
command string the command that I want to execute in the platform-specific terminal
env any optional key/value env variables object

getProfileIdByName

  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description
profileName string a valid named profile

getIdpUrlIdByUrl

  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description
url string the URL associated with the IdpUrl I want to retrieve

Example: display a toast message in Leapp

this.pluginEnvironment.log("Hello World", LogLevel.info, true);
 

Example: fetch basic usage

const res = await this.pluginEnvironment.fetch(""); //Insert a custom URL
 const response = await res.json();
 

Example: open a URL in the browser

this.pluginEnvironment.openExternalUrl("https://leapp.cloud");
@@ -100,4 +100,4 @@
     this.pluginEnvironment.openExternalUrl(loginURL);
   }
 }
-
\ No newline at end of file +
\ No newline at end of file diff --git a/latest/plugins/plugins-introduction/index.html b/latest/plugins/plugins-introduction/index.html index 6f90f783f..583da7aa3 100644 --- a/latest/plugins/plugins-introduction/index.html +++ b/latest/plugins/plugins-introduction/index.html @@ -1,4 +1,4 @@ - Introduction to Plugins - Leapp - Docs

Introduction to Plugins

This section provides an overview of Leapp’s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

Add a Plugin

To add a plugin you can use one of the following methods:

Add from npm

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

Add manually

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

Disable a Plugin

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

Remove a Plugin

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

Run a Plugin

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

Plugin Menu

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

Create your Plugin

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             
+ Introduction to Plugins - Leapp - Docs      

Introduction to Plugins

This section provides an overview of Leapp’s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

Add a Plugin

To add a plugin you can use one of the following methods:

Add from npm

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

Add manually

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

Disable a Plugin

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

Remove a Plugin

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

Run a Plugin

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

Plugin Menu

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

Create your Plugin

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             
  ├── package.json      # Plugin metadata
  └── plugin.js         # A webpack bundle for the main logic
-

Create your Plugin

\ No newline at end of file +

Create your Plugin

\ No newline at end of file diff --git a/latest/search/search_index.json b/latest/search/search_index.json index 570a82e7f..31edc17af 100644 --- a/latest/search/search_index.json +++ b/latest/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Overview","text":""},{"location":"#overview","title":"Overview","text":""},{"location":"#welcome-to-leapp","title":"Welcome to Leapp","text":"

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

"},{"location":"#introducing-leapp-cli","title":"Introducing Leapp CLI","text":"

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

"},{"location":"configuration/","title":"Add your first configuration","text":"

Now it's time to add your very first configuration. Follow the link to your preferred supported method and start enjoying Leapp.

"},{"location":"configuration/#sessions","title":"Sessions","text":""},{"location":"configuration/#aws","title":"AWS","text":"

Select the configuration you need from the Access Method dropdown menu:

Leapp Iam User

Then follow the links below.

  • Configure an AWS IAM User
  • Configure an AWS IAM Role Federated
  • Configure an AWS IAM Role Chained
  • Configure LocalStack
"},{"location":"configuration/#integrations","title":"Integrations","text":""},{"location":"configuration/#aws-sso","title":"AWS SSO","text":"
  • Configure AWS SSO
"},{"location":"configuration/#azure-ad","title":"Azure AD","text":"
  • Configure an Azure Tenant
"},{"location":"edit-session/","title":"Editing a session","text":"

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can\u2019t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select \"edit session\". A new modal will appear, allowing the user to choose which parameters to change.

edit session

Below are the configuration options for every type of session:

"},{"location":"edit-session/#iam-user","title":"Iam User","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault
"},{"location":"edit-session/#iam-role-chained","title":"IAM Role Chained","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing \"Create Chained Session\"

"},{"location":"edit-session/#iam-role-federated","title":"IAM Role Federated","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

"},{"location":"edit-session/#how-we-handle-secrets-when-editing-a-session","title":"How we handle Secrets when Editing a Session","text":"

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

"},{"location":"integrations/","title":"Integrations","text":"

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

"},{"location":"integrations/#actions","title":"Actions","text":"

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description CREATE Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions. DELETE Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.) SYNC Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status. LOGOUT Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it."},{"location":"integrations/#supported-services","title":"Supported Services","text":"Service Supported AWS SSO Okta Coming Soon OneLogin Coming Soon AzureAD"},{"location":"sessions/","title":"Sessions","text":""},{"location":"sessions/#sessions","title":"Sessions","text":"

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

"},{"location":"sessions/#actions","title":"Actions","text":"Method Description START \u00a0Make the temporary credentials available to the provider chain STOP \u00a0Removes the temporary credentials from the provider chain ROTATE \u00a0Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

"},{"location":"workspaces/","title":"Workspaces","text":""},{"location":"workspaces/#workspaces","title":"Workspaces","text":"

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

"},{"location":"workspaces/#local","title":"Local","text":"

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

"},{"location":"workspaces/#remote","title":"Remote","text":"

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

"},{"location":"workspaces/#actions","title":"Actions","text":"

The actions below only applies to Remote workspaces.

Action Description Sign-in \u00a0Connect to a Remote workspace. This action will not switch your Local workspace Switch \u00a0Switch to the selected workspace by clicking on its name in the workspace menu Lock \u00a0Switch back to the Local workspace disabling all the Remote ones Sign-out \u00a0Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

"},{"location":"built-in-features/aws-ec2-connect/","title":"Configure AWS EC2 Connect","text":""},{"location":"built-in-features/aws-ec2-connect/#what-is-aws-ec2-connect","title":"What is AWS EC2 Connect","text":"

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

"},{"location":"built-in-features/aws-ec2-connect/#how-to-configure-aws-ec2-connect-in-leapp","title":"How To configure AWS EC2 Connect in Leapp","text":"

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.
"},{"location":"built-in-features/aws-ec2-connect/#video-tutorial","title":"Video tutorial","text":"

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

"},{"location":"built-in-features/aws-named-profiles/","title":"Configure Named Profiles","text":""},{"location":"built-in-features/aws-named-profiles/#what-is-a-named-profile","title":"What is a Named Profile","text":"

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

"},{"location":"built-in-features/aws-named-profiles/#how-to-configure-a-named-profile-in-leapp","title":"How to configure a Named Profile in Leapp","text":"

Named Profiles can be created in 3 ways:

Option PanelWhen creating a new SessionEdit Profile in Contextual Menu

Click on the gear icon and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the \"Change Profile\" option in the session list.

"},{"location":"built-in-features/aws-named-profiles/#named-profile-list","title":"Named Profile List","text":"

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

"},{"location":"built-in-features/general-options/","title":"General Options","text":"

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

"},{"location":"built-in-features/general-options/#default-regions","title":"Default Regions","text":"

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

"},{"location":"built-in-features/general-options/#terminal-selection","title":"Terminal Selection","text":"

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

"},{"location":"built-in-features/general-options/#color-theme","title":"Color Theme","text":"

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

"},{"location":"built-in-features/general-options/#default-webconsole-duration","title":"Default Webconsole Duration","text":"

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

"},{"location":"built-in-features/multi-console/","title":"Configure Multi Console","text":""},{"location":"built-in-features/multi-console/#what-is-multi-console","title":"What is Multi Console","text":"

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

Get it on Firefox \u21e9 Get it on Chrome \u21e9"},{"location":"built-in-features/multi-console/#list-of-supported-browsers","title":"List of Supported Browsers","text":"Browser Supported Firefox Chrome Edge Brave Safari"},{"location":"built-in-features/multi-console/#how-to-configure-multi-console-in-leapp","title":"How to Configure Multi Console in Leapp","text":""},{"location":"built-in-features/multi-console/#install-the-extension","title":"Install the Extension","text":""},{"location":"built-in-features/multi-console/#firefox","title":"Firefox","text":"

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox \u21e9

"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers","title":"Chrome, Edge and other Chromium based browsers","text":"

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others \u21e9

"},{"location":"built-in-features/multi-console/#uninstall-the-extension","title":"Uninstall the Extension","text":""},{"location":"built-in-features/multi-console/#firefox_1","title":"Firefox","text":"
  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove
"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers_1","title":"Chrome, Edge and other Chromium based browsers","text":"
  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select \"Cookies\". Then, remove all cookies by clicking \"Remove\" until the cookie list is empty and finally click on Done

"},{"location":"built-in-features/multi-console/#how-to-use-it","title":"How to use it","text":"

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).

By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

"},{"location":"built-in-features/opening-web-console/","title":"Configure Open Web Console","text":""},{"location":"built-in-features/opening-web-console/#what-is-open-web-console","title":"What is Open Web Console","text":"

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

"},{"location":"built-in-features/opening-web-console/#how-to-configure-open-web-console-in-leapp","title":"How to Configure Open Web Console in Leapp","text":"

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

"},{"location":"cli/","title":"Index","text":"

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli\n$ leapp COMMAND\nrunning command...\n$ leapp (--version)\n@noovolari/leapp-cli/0.1.65 darwin-x64 node-v21.6.2\n$ leapp --help [COMMAND]\nUSAGE\n  $ leapp COMMAND\n...\n
"},{"location":"cli/#command-topics","title":"Command Topics","text":"
  • leapp help - Display help for leapp.
  • leapp idp-url - SAML 2.0 Identity providers URL management
  • leapp integration - Leapp Integrations management
  • leapp profile - Leapp AWS Multi-profile management
  • leapp region - Leapp regions management
  • leapp session - Sessions management
  • leapp set-workspace - Set the current Leapp workspace
  • leapp team - Login to your Team account
  • leapp version - Displays the Cli and Core versions
  • leapp workspace - Show the current workspace
"},{"location":"cli/scopes/help/","title":"Help","text":""},{"location":"cli/scopes/help/#leapp-help","title":"leapp help","text":"

Display help for leapp.

  • leapp help [COMMANDS]
"},{"location":"cli/scopes/help/#leapp-help-commands","title":"leapp help [COMMANDS]","text":"

Display help for leapp.

USAGE\n  $ leapp help [COMMANDS] [-n]\n\nARGUMENTS\n  COMMANDS  Command to show help for.\n\nFLAGS\n  -n, --nested-commands  Include all nested commands in the output.\n\nDESCRIPTION\n  Display help for leapp.\n

See code: @oclif/plugin-help

"},{"location":"cli/scopes/idp-url/","title":"Idp Url","text":""},{"location":"cli/scopes/idp-url/#leapp-idp-url","title":"leapp idp-url","text":"

SAML 2.0 Identity providers URL management

  • leapp idp-url create
  • leapp idp-url delete
  • leapp idp-url edit
  • leapp idp-url list
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-create","title":"leapp idp-url create","text":"

Create a new identity provider URL

USAGE\n  $ leapp idp-url create [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>  the idp url address we want to create\n\nDESCRIPTION\n  Create a new identity provider URL\n\nEXAMPLES\n  $leapp idp-url create\n\n  $leapp idp-url create --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-delete","title":"leapp idp-url delete","text":"

Delete an identity provider URL

USAGE\n  $ leapp idp-url delete [--idpUrlId <value>] [-f]\n\nFLAGS\n  -f, --force         force a command without asking for confirmation (-f, --force)\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Delete an identity provider URL\n\nEXAMPLES\n  $leapp idp-url delete\n\n  $leapp idp-url delete --idpUrlId ID\n\n  $leapp idp-url delete --idpUrlId ID [--force, -f]\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-edit","title":"leapp idp-url edit","text":"

Edit an identity provider URL

USAGE\n  $ leapp idp-url edit [--idpUrlId <value>] [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>    the idp url address we want to create\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Edit an identity provider URL\n\nEXAMPLES\n  $leapp idp-url edit\n\n  $leapp idp-url edit --idpUrlId ID --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-list","title":"leapp idp-url list","text":"

Show identity providers list

USAGE\n  $ leapp idp-url list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show identity providers list\n\nEXAMPLES\n  $leapp idp-url list\n
"},{"location":"cli/scopes/integration/","title":"Integration","text":""},{"location":"cli/scopes/integration/#leapp-integration","title":"leapp integration","text":"

Leapp Integrations management

  • leapp integration create
  • leapp integration delete
  • leapp integration list
  • leapp integration login
  • leapp integration logout
  • leapp integration sync
"},{"location":"cli/scopes/integration/#leapp-integration-create","title":"leapp integration create","text":"

Create a new integration

USAGE\n  $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]\n    [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]\n\nFLAGS\n  --integrationAlias=<value>      alias that identifies an integration\n  --integrationLocation=<value>   Location of an Azure Integration\n  --integrationPortalUrl=<value>  url that identifies the integration portal where you authenticate\n  --integrationRegion=<value>     an AWS valid region code for the integration\n  --integrationTenantId=<value>   Tenant ID of an Azure Integration\n  --integrationType=<option>      Identify the type of your integration. Valid types are [AWS-SSO, AZURE]\n                                  <options: AWS-SSO|AZURE>\n\nDESCRIPTION\n  Create a new integration\n\nEXAMPLES\n  $leapp integration create\n\n  $leapp integration create --integrationType AWS-SSO --integrationAlias ALIAS --integrationPortalUrl URL --integrationRegion REGION\n\n  $leapp integration create --integrationType AZURE --integrationAlias ALIAS --integrationTenantId TENANT --integrationLocation LOCATION\n
"},{"location":"cli/scopes/integration/#leapp-integration-delete","title":"leapp integration delete","text":"

Delete an integration

USAGE\n  $ leapp integration delete [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Delete an integration\n\nEXAMPLES\n  $leapp integration delete\n\n  $leapp integration delete --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-list","title":"leapp integration list","text":"

Show integrations list

USAGE\n  $ leapp integration list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show integrations list\n\nEXAMPLES\n  $leapp integration list\n
"},{"location":"cli/scopes/integration/#leapp-integration-login","title":"leapp integration login","text":"

Login to synchronize integration sessions

USAGE\n  $ leapp integration login [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Login to synchronize integration sessions\n\nEXAMPLES\n  $leapp integration login\n\n  $leapp integration login --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-logout","title":"leapp integration logout","text":"

Logout from an integration

USAGE\n  $ leapp integration logout [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Logout from an integration\n\nEXAMPLES\n  $leapp integration logout\n\n  $leapp integration logout --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-sync","title":"leapp integration sync","text":"

Synchronize integration sessions

USAGE\n  $ leapp integration sync [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Synchronize integration sessions\n\nEXAMPLES\n  $leapp integration sync\n\n  $leapp integration sync --integrationId ID\n
"},{"location":"cli/scopes/profile/","title":"Profile","text":""},{"location":"cli/scopes/profile/#leapp-profile","title":"leapp profile","text":"

Leapp AWS Multi-profile management

  • leapp profile create
  • leapp profile delete
  • leapp profile edit
  • leapp profile list
"},{"location":"cli/scopes/profile/#leapp-profile-create","title":"leapp profile create","text":"

Create a new AWS named profile

USAGE\n  $ leapp profile create [--profileName <value>]\n\nFLAGS\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Create a new AWS named profile\n\nEXAMPLES\n  $leapp profile create\n\n  $leapp profile create --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-delete","title":"leapp profile delete","text":"

Delete an AWS named profile

USAGE\n  $ leapp profile delete [--profileId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --profileId=<value>  an AWS named profile ID in Leapp\n\nDESCRIPTION\n  Delete an AWS named profile\n\nEXAMPLES\n  $leapp profile delete\n\n  $leapp profile delete --profileId PROFILEID\n\n  $leapp profile delete --profileId PROFILEID [--force, -f]\n
"},{"location":"cli/scopes/profile/#leapp-profile-edit","title":"leapp profile edit","text":"

Rename an AWS named profile

USAGE\n  $ leapp profile edit [--profileId <value>] [--profileName <value>]\n\nFLAGS\n  --profileId=<value>    an AWS named profile ID in Leapp\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Rename an AWS named profile\n\nEXAMPLES\n  $leapp profile edit\n\n  $leapp profile edit --profileId ID --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-list","title":"leapp profile list","text":"

Show profile list

USAGE\n  $ leapp profile list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show profile list\n\nEXAMPLES\n  $leapp profile list\n
"},{"location":"cli/scopes/region/","title":"Region","text":""},{"location":"cli/scopes/region/#leapp-region","title":"leapp region","text":"

Leapp regions management

  • leapp region get-default
  • leapp region set-default
"},{"location":"cli/scopes/region/#leapp-region-get-default","title":"leapp region get-default","text":"

Displays the default region

USAGE\n  $ leapp region get-default\n\nDESCRIPTION\n  Displays the default region\n\nEXAMPLES\n  $leapp region get-default\n
"},{"location":"cli/scopes/region/#leapp-region-set-default","title":"leapp region set-default","text":"

Change the default region

USAGE\n  $ leapp region set-default [--region <value>]\n\nFLAGS\n  --region=<value>  Session Region for AWS sessions in Leapp\n\nDESCRIPTION\n  Change the default region\n\nEXAMPLES\n  $leapp region set-default\n\n  $leapp region set-default --region AWSREGION\n
"},{"location":"cli/scopes/session/","title":"Session","text":""},{"location":"cli/scopes/session/#leapp-session","title":"leapp session","text":"

Sessions management

  • leapp session add
  • leapp session change-profile
  • leapp session change-region
  • leapp session current
  • leapp session delete
  • leapp session generate SESSIONID
  • leapp session get-id
  • leapp session list
  • leapp session open-web-console
  • leapp session run-aws-credential-plugin
  • leapp session start [SESSIONNAME]
  • leapp session start-ssm-session
  • leapp session stop [SESSIONNAME]
"},{"location":"cli/scopes/session/#leapp-session-add","title":"leapp session add","text":"

Add a new session

USAGE\n  $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]\n    [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]\n    [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType\n    awsIamRoleFederated|awsIamUser|awsIamRoleChained]\n\nFLAGS\n  --accessKey=<value>        AWS Access Key ID of the IAM User\n  --idpArn=<value>           AWS IAM Federated Role IdP Arn value, obtain it from your AWS Account\n  --idpUrl=<value>           the idp url address we want to create\n  --mfaDevice=<value>        MFA Device Arn retrieved from your AWS Account\n  --parentSessionId=<value>  For AWS IAM Role Chained is the session Id of the session that will assume the chained\n                             role. Retrieve it using $leapp session list -x\n  --profileId=<value>        an AWS named profile ID in Leapp\n  --providerType=<option>    Identify the provider for your sessions. Valid types are [aws]\n                             <options: aws>\n  --region=<value>           Session Region for AWS sessions in Leapp\n  --roleArn=<value>          AWS IAM Federated Role Arn value, obtain it from your AWS Account\n  --roleSessionName=<value>  Optional Alias for the Assumed Role Session name\n  --secretKey=<value>        AWS Secret Access Key of the IAM User\n  --sessionName=<value>      Session Alias to identify the session in Leapp\n  --sessionType=<option>     Identify the AWS session type. Valid types are [awsIamRoleFederated, awsIamUser,\n                             awsIamRoleChained]\n                             <options: awsIamRoleFederated|awsIamUser|awsIamRoleChained>\n\nDESCRIPTION\n  Add a new session\n\nEXAMPLES\n  $leapp session add\n\n  $leapp session add --providerType [aws] --sessionType [awsIamRoleFederated, awsIamRoleChained, awsIamUser] --region [AWSREGION] --sessionName NAME ...[combination of flags relative to the session]\n\n  $leapp session add --providerType aws --sessionType awsIamRoleFederated --sessionName NAME --region AWSREGION --idpArn IDPARN --idpUrl IDPURL --profileId PROFILEID --roleArn ROLEARN\n\n  $leapp session add --providerType aws --sessionType awsIamRoleChained --sessionName NAME --region AWSREGION --profileId PROFILEID --roleArn ROLEARN --parentSessionId ID (--roleSessionName ROLESESSIONNAME)\n\n  $leapp session add --providerType aws --sessionType awsIamUser --sessionName NAME --region AWSREGION --profileId PROFILEID --accessKey ACCESSKEY --secretKey SECRETKEY (--mfaDevice MFADEVICEARN)\n
"},{"location":"cli/scopes/session/#leapp-session-change-profile","title":"leapp session change-profile","text":"

Change a session named-profile

USAGE\n  $ leapp session change-profile [--sessionId <value>] [--profileId <value>]\n\nFLAGS\n  --profileId=<value>  an AWS named profile ID in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session named-profile\n\nEXAMPLES\n  $leapp session change-profile\n\n  $leapp session change-profile --profileId PROFILEID --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-change-region","title":"leapp session change-region","text":"

Change a session region

USAGE\n  $ leapp session change-region [--sessionId <value>] [--region <value>]\n\nFLAGS\n  --region=<value>     Session Region for AWS sessions in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session region\n\nEXAMPLES\n  $leapp session change-region\n\n  $leapp session change-region --sessionId SESSIONID --region REGION\n
"},{"location":"cli/scopes/session/#leapp-session-current","title":"leapp session current","text":"

Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile default)

USAGE\n  $ leapp session current [-i] [-p <value>] [-r aws|azure] [-f <value>]\n\nFLAGS\n  -f, --format=<value>     allows formatting data to show\n                           - aws -> id alias, accountNumber, roleArn\n                           - azure -> id tenantId, subscriptionId\n  -i, --inline\n  -p, --profile=<value>    [default: default] aws named profile of which gets info\n  -r, --provider=<option>  filters sessions by the cloud provider service\n                           <options: aws|azure>\n\nDESCRIPTION\n  Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile\n  default)\n\nEXAMPLES\n  $leapp session current --format \"alias accountNumber\" --inline --provider aws\n
"},{"location":"cli/scopes/session/#leapp-session-delete","title":"leapp session delete","text":"

Delete a session

USAGE\n  $ leapp session delete [--sessionId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Delete a session\n\nEXAMPLES\n  $leapp session delete\n\n  $leapp session delete --sessionId SESSIONID\n\n  $leapp session delete --sessionId SESSIONID [--force, -f]\n
"},{"location":"cli/scopes/session/#leapp-session-generate-sessionid","title":"leapp session generate SESSIONID","text":"

Generate STS temporary credentials for the given AWS session id

USAGE\n  $ leapp session generate SESSIONID\n\nARGUMENTS\n  SESSIONID  id of the session\n\nDESCRIPTION\n  Generate STS temporary credentials for the given AWS session id\n\nEXAMPLES\n  $leapp session generate 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d\n
"},{"location":"cli/scopes/session/#leapp-session-get-id","title":"leapp session get-id","text":"

Get session id

USAGE\n  $ leapp session get-id\n\nDESCRIPTION\n  Get session id\n\nEXAMPLES\n  $leapp session get-id\n
"},{"location":"cli/scopes/session/#leapp-session-list","title":"leapp session list","text":"

Show sessions list with all properties; filter query is case sensitive

USAGE\n  $ leapp session list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show sessions list with all properties; filter query is case sensitive\n\nEXAMPLES\n  $leapp session list\n\n  $leapp session list --filter=\"ID=Foo\" -x\n\n  $leapp session list --filter=\"Session Name=Foo\"\n\n  $leapp session list --filter=\"Type=Foo\"\n\n  $leapp session list --filter=\"Named Profile=Foo\"\n\n  $leapp session list --filter=\"Region/Location=Foo\"\n\n  $leapp session list --filter=\"Status=Foo\"\n
"},{"location":"cli/scopes/session/#leapp-session-open-web-console","title":"leapp session open-web-console","text":"

Open an AWS Web Console

USAGE\n  $ leapp session open-web-console [--sessionId <value>] [-p]\n\nFLAGS\n  -p, --print          Print an AWS Web Console login URL in the terminal instead of opening the web browser\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Open an AWS Web Console\n\nEXAMPLES\n  $leapp session open-web-console\n\n  $leapp session open-web-console --sessionId SESSIONID [--print, -p]\n
"},{"location":"cli/scopes/session/#leapp-session-run-aws-credential-plugin","title":"leapp session run-aws-credential-plugin","text":"

Run a Leapp Plugin

USAGE\n  $ leapp session run-aws-credential-plugin [--sessionId <value>] [--pluginName <value>]\n\nFLAGS\n  --pluginName=<value>  Unique name of a Leapp Plugin\n  --sessionId=<value>   Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Run a Leapp Plugin\n\nEXAMPLES\n  $leapp session run-plugin\n\n  $leapp session run-plugin --sessionName SESSIONAME --pluginName PLUGINNAME\n
"},{"location":"cli/scopes/session/#leapp-session-start-sessionname","title":"leapp session start [SESSIONNAME]","text":"

Start a session

USAGE\n  $ leapp session start [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Start a session\n\nEXAMPLES\n  $leapp session start\n\n  $leapp session start SESSIONNAME\n\n  $leapp session start SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session start SESSIONNAME --noInteractive\n\n  $leapp session start --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-start-ssm-session","title":"leapp session start-ssm-session","text":"

Start an AWS SSM session

USAGE\n  $ leapp session start-ssm-session [--sessionId <value>] [--region <value>] [--ssmInstanceId <value>]\n\nFLAGS\n  --region=<value>         Session Region for AWS sessions in Leapp\n  --sessionId=<value>      Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --ssmInstanceId=<value>  Instance ID for EC2 instance we want to access with SSM\n\nDESCRIPTION\n  Start an AWS SSM session\n\nEXAMPLES\n  $leapp session start-ssm-session\n\n  $leapp session start-ssm-session --sessionId SESSIONID --region AWSREGION --ssmInstanceId EC2INSTANCEID\n
"},{"location":"cli/scopes/session/#leapp-session-stop-sessionname","title":"leapp session stop [SESSIONNAME]","text":"

Stop a session

USAGE\n  $ leapp session stop [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Stop a session\n\nEXAMPLES\n  $leapp session stop\n\n  $leapp session stop SESSIONNAME\n\n  $leapp session stop SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session stop SESSIONNAME --noInteractive\n\n  $leapp session stop --sessionId SESSIONID\n
"},{"location":"cli/scopes/set-workspace/","title":"Set Workspace","text":""},{"location":"cli/scopes/set-workspace/#leapp-set-workspace","title":"leapp set-workspace","text":"

Set the current Leapp workspace

  • leapp set-workspace [WORKSPACENAME]
"},{"location":"cli/scopes/set-workspace/#leapp-set-workspace-workspacename","title":"leapp set-workspace [WORKSPACENAME]","text":"

Set the current Leapp workspace

USAGE\n  $ leapp set-workspace [WORKSPACENAME]\n\nARGUMENTS\n  WORKSPACENAME  name of the Leapp Team remote workspace or local\n\nDESCRIPTION\n  Set the current Leapp workspace\n\nEXAMPLES\n  $leapp team set-workspace\n\n  $leapp team set-workspace local\n\n  $leapp team set-workspace WORKSPACE-NAME\n

See code: dist/commands/set-workspace.ts

"},{"location":"cli/scopes/team/","title":"Team","text":""},{"location":"cli/scopes/team/#leapp-team","title":"leapp team","text":"

Login to your Team account

  • leapp team login
  • leapp team logout
  • leapp team status
"},{"location":"cli/scopes/team/#leapp-team-login","title":"leapp team login","text":"

Login to your Team account

USAGE\n  $ leapp team login\n\nDESCRIPTION\n  Login to your Team account\n\nEXAMPLES\n  $leapp team login\n
"},{"location":"cli/scopes/team/#leapp-team-logout","title":"leapp team logout","text":"

Logout from your Team account

USAGE\n  $ leapp team logout\n\nDESCRIPTION\n  Logout from your Team account\n\nEXAMPLES\n  $leapp team logout\n
"},{"location":"cli/scopes/team/#leapp-team-status","title":"leapp team status","text":"

Get the team login status

USAGE\n  $ leapp team status\n\nDESCRIPTION\n  Get the team login status\n\nEXAMPLES\n  $leapp team status\n
"},{"location":"cli/scopes/version/","title":"Version","text":""},{"location":"cli/scopes/version/#leapp-version","title":"leapp version","text":"

Displays the Cli and Core versions

  • leapp version
"},{"location":"cli/scopes/version/#leapp-version_1","title":"leapp version","text":"

Displays the Cli and Core versions

USAGE\n  $ leapp version\n\nDESCRIPTION\n  Displays the Cli and Core versions\n\nEXAMPLES\n  $leapp version\n

See code: dist/commands/version.ts

"},{"location":"cli/scopes/workspace/","title":"Workspace","text":""},{"location":"cli/scopes/workspace/#leapp-workspace","title":"leapp workspace","text":"

Show the current workspace

  • leapp workspace
"},{"location":"cli/scopes/workspace/#leapp-workspace_1","title":"leapp workspace","text":"

Show the current workspace

USAGE\n  $ leapp workspace\n\nDESCRIPTION\n  Show the current workspace\n\nEXAMPLES\n  $leapp workspace\n

See code: dist/commands/workspace.ts

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/","title":"Configure an AWS Identity Center (ex AWS Single Sign-On) integration","text":""},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#what-is-aws-identity-center-ex-aws-single-sign-on","title":"What is AWS Identity Center (ex AWS Single Sign-On)","text":"

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#how-to-configure-an-aws-identity-center-ex-aws-single-sign-on-integration-in-leapp","title":"How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as AWS Single Sign-on AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start. REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part."},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-integration/configure-azure-integration/","title":"Configure an Azure integration","text":""},{"location":"configuring-integration/configure-azure-integration/#what-is-an-azure-integration","title":"What is an Azure integration","text":"

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

"},{"location":"configuring-integration/configure-azure-integration/#how-to-configure-an-azure-integration-in-leapp","title":"How to configure an Azure integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-azure-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as Azure ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database. LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options."},{"location":"configuring-integration/configure-azure-integration/#video-tutorial","title":"Video tutorial","text":"

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

"},{"location":"configuring-session/configure-aws-iam-role-chained/","title":"Configure AWS IAM Role Chained","text":""},{"location":"configuring-session/configure-aws-iam-role-chained/#what-is-an-aws-iam-role-chained-session","title":"What is an AWS IAM Role Chained session","text":"

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

"},{"location":"configuring-session/configure-aws-iam-role-chained/#how-to-configure-an-aws-iam-role-chained-in-leapp","title":"How to configure an AWS IAM Role Chained in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-chained/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role. ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity. ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp."},{"location":"configuring-session/configure-aws-iam-role-chained/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/","title":"Configure AWS IAM Role Federated","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/#what-is-an-aws-iam-role-federated-session","title":"What is an AWS IAM Role Federated session","text":"

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#supported-saml-identity-providers","title":"Supported SAML Identity Providers","text":"Identity Provider AWS Azure GSUITE OKTA ONELOGIN AZURE AD AUTH0 KEYCLOAK JUMPCLOUD

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

"},{"location":"configuring-session/configure-aws-iam-role-federated/#how-to-configure-an-aws-iam-role-federated-in-leapp","title":"How to configure an AWS IAM Role Federated in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider. AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role."},{"location":"configuring-session/configure-aws-iam-role-federated/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-user/","title":"Configure AWS IAM User","text":""},{"location":"configuring-session/configure-aws-iam-user/#what-is-an-aws-iam-user-session","title":"What is an AWS IAM User session","text":"

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

"},{"location":"configuring-session/configure-aws-iam-user/#how-to-configure-an-aws-iam-user-in-leapp","title":"How to configure an AWS IAM User in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-user/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. MFA DEVICE Your MFA device ID to set up multi-factor authentication. ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. Add AWS IAM User Screen"},{"location":"configuring-session/configure-aws-iam-user/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-localstack/","title":"Configure LocalStack","text":""},{"location":"configuring-session/configure-localstack/#what-is-a-localstack-session","title":"What is a LocalStack session","text":"

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

"},{"location":"configuring-session/configure-localstack/#how-to-configure-a-localstack-session-in-leapp","title":"How to configure a LocalStack session in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

"},{"location":"contributing/get-involved/","title":"Get involved","text":""},{"location":"contributing/get-involved/#get-involved","title":"Get involved","text":"

Contributions and questions are not just welcome, they\u2019re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you\u2019re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you.

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

"},{"location":"installation/install-leapp/","title":"Install Leapp","text":""},{"location":"installation/install-leapp/#install-leapp-app","title":"Install Leapp App","text":""},{"location":"installation/install-leapp/#macos-windows-and-linux","title":"MacOS, Windows, and Linux","text":"

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp \u21e9

Unzip the package and double-click the executable to install.

"},{"location":"installation/install-leapp/#macos-homebrew","title":"macOS (Homebrew)","text":"

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp\n

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

"},{"location":"installation/install-leapp/#install-leapp-cli","title":"Install Leapp CLI","text":"

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli\n

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli\n
"},{"location":"installation/install-leapp/#install-leapp-cli-on-macos-with-arm64-chip-m1-m2","title":"Install Leapp CLI on macOS with ARM64 chip (M1, M2)","text":"

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64\n

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

"},{"location":"installation/requirements/","title":"Requirements","text":""},{"location":"installation/requirements/#requirements","title":"Requirements","text":""},{"location":"installation/requirements/#macos-and-windows","title":"MacOS and Windows","text":"

There are no requirements for macOS and Windows users.

"},{"location":"installation/requirements/#linux-systems","title":"Linux systems","text":"

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

Arch LinuxDebian/UbuntuRed Hat-based
sudo pacman -S gnome-keyring\nsudo pacman -S libsecret\n
sudo apt-get install gnome-keyring\nsudo apt-get install libsecret-1-dev\n
sudo yum install gnome-keyring\nsudo yum install libsecret-devel\n
"},{"location":"installation/requirements/#logging-into-ec2-instances-via-aws-ssm-with-leapp","title":"Logging into EC2 Instances via AWS SSM with Leapp","text":"

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>\n

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/\n

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html\n
"},{"location":"installation/update-leapp/","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#update-leapp","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#desktop-app","title":"Desktop App","text":"

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Remind me laterDownload updateClick on X

Leapp will close the modal and notify the user that a new update is available by adding a notification dot to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

"},{"location":"installation/update-leapp/#macos-homebrew-linux-linuxbrew-and-windows-via-wsl","title":"macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)","text":"

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

"},{"location":"installation/update-leapp/#cli","title":"CLI","text":"

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npmHomebrew (macOS)
npm update -g @noovolari/leapp-cli\n
brew upgrade Noovolari/brew/leapp-cli\n
"},{"location":"leapp-pro/export-pro-workspace/","title":"Export PRO Workspace","text":""},{"location":"leapp-pro/export-pro-workspace/#how-to-export-your-pro-workspace","title":"How to export your Pro Workspace","text":"
  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:\ncp Leapp-lock.json Leapp-lock.json.bkp\n
  2. log into you Pro Workspace using the Desktop App;

  3. from the Leapp Options \"General\" tab, click the button next to the \"Export Pro/Team workspace\" label;

  4. close the Leapp Options dialog;

  5. close Leapp (on macOS \u2318+Q);
  6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
  7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
    rm Leapp-lock.json\nmv Leapp-lock.json.exported Leapp-lock.json\n
  8. re-open Leapp;
  9. switch to the Local Workspace;
  10. you should now see your Pro Workspace migrated into the Local one.
"},{"location":"leapp-pro/security-and-password/","title":"Security and password","text":""},{"location":"leapp-pro/security-and-password/#password-issues","title":"Password issues","text":""},{"location":"leapp-pro/security-and-password/#can-i-recover-my-password","title":"Can I recover my password?","text":"

Unfortunately, it is not possible to recover the master password. The master password is very important as it's the key point of our zero-knowledge encryption mechanism. If you forget it, you'll lose access to the previously encrypted Leapp Sessions and Integrations. That's why it is crucial that you keep your password safe; we suggest you to store it in a password manager like 1Password.

"},{"location":"leapp-pro/security-and-password/#how-is-my-data-encrypted","title":"How is my data encrypted?","text":"

All information associated with your stored data is protected with end-to-end encryption. Leapp Sessions and Integrations are encrypted before being forwarded to the backend. Specifically, Leapp Pro uses AES 256-bit encryption as well as PBKDF-SHA512 to secure your data.

AES is a standard in cryptography and is used by the U.S. government and other government agencies around the world for protecting top-secret data. With proper implementation and a strong encryption key (your Master Password), AES is considered unbreakable.

PBKDF-SHA512 is used to derive the encryption key from your master password. Then this key is salted and hashed for authenticating with the Leapp Pro backend. The default iteration count used with PBKDF2 is 500,000 iterations on the client. Each Secret has its own generated symmetric key; this symmetric key is encrypted using the user\u2019s public RSA key (this is also the foundation of the Secret sharing system). This encryption and decryption are done entirely on the Leapp Pro clients because your master password is never stored on or transmitted to Leapp Team backend.

It is important to highlight the fact that the backend does not act as a credentials broker, i.e. it has no visibility on the long-term/short-term credentials used by Leapp Pro Desktop App/CLI to access the cloud providers. In addition, the secrets retrieved from the backend, are an encrypted version of access configurations; access configurations DO NOT include temporary credentials. There is a single edge case: the IAM User. Indeed, the IAM User Session access configuration contains IAM User\u2019s access keys, which are long-term credentials. Still, the Leapp Pro backend has no visibility on these long-term credentials, as they\u2019re encrypted by the client before being forwarded to the Leapp Team backend.

"},{"location":"leapp-pro/security-and-password/#touch-id","title":"Touch ID","text":"

When you unlock Leapp Pro, using a longer and more secure account password is easier than you might otherwise have chosen.

"},{"location":"leapp-pro/security-and-password/#your-fingerprint-is-not-stored-in-leapp","title":"Your fingerprint is not stored in Leapp.","text":"

Leapp never scans or stores your fingerprint. Touch ID is provided by macOS, which only tells Leapp Pro if your fingerprint was recognized or not.

Learn more about Touch ID's advanced security technology.

"},{"location":"leapp-pro/synchronization/","title":"Synchronization","text":""},{"location":"leapp-pro/synchronization/#whats-a-pro-workspace","title":"What's a Pro Workspace","text":"

A Pro Workspace is a new Workspace that is created upon first login with your registered Pro User. This workspace is synchronized with your Cloud account every time you create, edit, or delete an integration or a session; this way it is possible to use Leapp Pro on different devices, maintaining all your saved integrations and sessions.

"},{"location":"leapp-pro/synchronization/#how-the-synchronization-works","title":"How the Synchronization works","text":"

Synchronization works by encrypting all your sessions and integrations with your master password, created during your sign-up process. This way we maintain a 0-knowlegde approach on your data through all the lifecycle of your Pro workspace.

The encrypted data is then saved in the Cloud on your Leapp Pro personal space.

You, as a Leapp Pro user, can always keep an eye on the status of synchronization using the synchronization widget in the bottom-left area of Leapp.

Synchronization widget - synchronization active and done

When all the data is correctly synchronized you'll see the image above.

When Leapp Pro is synchronizing you'll see the icon and text changing to the one in the image below.

Synchronization widget - synchronization in progress

If you eventually lose connection or have a problem in synchronizing your data the widget will turn yellow as shown below.

Synchronization widget - synchronization failed

You have the possibility to manually trigger another synchronization process and see if the problem is resolved.

Info

When Leapp Pro is restarted it will try to synchronize your data in the Cloud if you're logged in, so you can also close Leapp safely even if in synch failed state.

"},{"location":"leapp-pro/synchronization/#do-you-have-any-trouble-with-synchronization","title":"Do you have any trouble with Synchronization","text":"

In case of any troubles locking Leapp Pro workspace please contact us.

"},{"location":"leapp-pro/getting-started/","title":"Getting Started","text":""},{"location":"leapp-pro/getting-started/#why-leapp-pro","title":"Why Leapp Pro?","text":"

Leapp Pro enable Users to protect their Cloud access with Username and password.

With Leapp Pro you can back up and synchronize your Leapp workspace and access to any device you want without losing your access configurations.

"},{"location":"leapp-pro/getting-started/#getting-started-guide","title":"Getting started guide","text":"
  • Sign up to Leapp Pro
  • Sign in to Leapp Pro
  • Lock your Leapp Pro Workspace
"},{"location":"leapp-pro/getting-started/#security-and-syncronization","title":"Security and syncronization","text":"

Once you updgrade your Plan to Leapp Pro, your local Workspace will be moved to the Pro Workspace. All the data inside your workspace are secured with end-to-end encryption through your Master password.

"},{"location":"leapp-pro/getting-started/lock/","title":"Lock your Workspace","text":"

Leapp Pro allows the user to temporary lock the workspace, making it accessible only by typing again your master-password. This feature provides a further security level on top of the standard Leapp Community edition.

"},{"location":"leapp-pro/getting-started/lock/#how-to-lock-the-leapp-pro-workspace","title":"How to lock the Leapp Pro workspace","text":"

To lock your Leapp Pro workspace you should click on the Workspace button located in the top-left area and select the Lock option.

Workspace button Lock option

The Leapp Pro lock screen should appear, prompting for your master-password.

Leapp Pro lock screen"},{"location":"leapp-pro/getting-started/lock/#touch-id","title":"Touch ID","text":"

You can also use your fingerprint to unlock Leapp if your PC is Touch ID compatible. After Logging to your Pro workspace for the first time, Leapp will associate your workspace with your system Touch ID. After that the option will be available and can also be tweaked in the general tab of the option menu.

"},{"location":"leapp-pro/getting-started/lock/#troubles-in-locking-your-workspace","title":"Troubles in locking your Workspace","text":"

In case of any troubles locking Leapp Pro workspace please contact us.

"},{"location":"leapp-pro/getting-started/sign-in/","title":"Sign-in","text":"

With Leapp Pro you can always sign-in from any location, gaining instant access to your personal workspace.

"},{"location":"leapp-pro/getting-started/sign-in/#sign-in-to-leapp-pro","title":"Sign-in to Leapp Pro","text":"

After upgrading Leapp Community edition, you can sign-in at any time, just clicking on the Workspace button located in the top-left area and selecting the Sign-in Workspace option.

Workspace button Sign-in Workspace option

The Sign-in Workspace dialog will appear. Enter your Email address, master-password and click on the Add Workspace button.

Sign-in dialog

If the information entered is correct, your Leapp Pro workspace will be displayed and you can immediately use it to manage your cloud credentials.

Leapp Pro Workspace

To avoid unwanted access, you can lock your Leapp Pro workspace at any time.

"},{"location":"leapp-pro/getting-started/sign-in/#troubles-in-signing-in-to-leapp-pro","title":"Troubles in signing in to Leapp Pro?","text":"

In case of any troubles signing in to Leapp Pro please contact us.

"},{"location":"leapp-pro/getting-started/sign-up/","title":"Sign-up","text":"

A Leapp Pro upgrade is required to enable new workspace features like Cloud access from multiple locations and Workspace locking.

"},{"location":"leapp-pro/getting-started/sign-up/#sign-up-to-leapp-pro","title":"Sign-up to Leapp Pro","text":"

To sign up for Leapp Pro you should upgrade your version of Leapp Community edition. Click on the Options button in the top-right area.

Settings button

In the Options dialog, select the Plans tab and click on Upgrade to Pro button.

Plans tab

The upgrade window should appear. Enter your email (it will be the email address associated with your Leapp Pro account) and click on the Upgrade now button.

Upgrade window

At this point a window will appear, so you can specify a payment method to complete the Leapp Pro upgrade. After the payment process you will receive a confirmation email containing the Complete the registration link.

Upgrade email

Clicking the link in the confirmation email will open a web page that will allow you to enter your personal info and the master-password, essential to provide the security requirements of Leapp Pro.

Sign-up page

After entering your personal info and the master-password click the Continue button. You can now finally sign in to Leapp Pro.

"},{"location":"leapp-pro/getting-started/sign-up/#troubles-in-signing-up-to-leapp-pro","title":"Troubles in signing up to Leapp Pro?","text":"

In case of any troubles signing up to Leapp Pro please contact us.

"},{"location":"leapp-pro/getting-started/sign-up/#how-to-sign-in","title":"How to Sign-in","text":"

Take a look to this page to sign-in your Leapp Pro workspace.

"},{"location":"plugins/plugins-development/","title":"Developer Reference","text":"

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

"},{"location":"plugins/plugins-development/#pluginenvironment","title":"PluginEnvironment","text":"

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

"},{"location":"plugins/plugins-development/#log","title":"log","text":"
  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description message string the message to show level LogLevel severity of the message display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files"},{"location":"plugins/plugins-development/#fetch","title":"fetch","text":"
  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description url string a valid HTTP URL to fetch from"},{"location":"plugins/plugins-development/#openexternalurl","title":"openExternalUrl","text":"
  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description url string a valid HTTP URL to open in the default browser"},{"location":"plugins/plugins-development/#createsession","title":"createSession","text":"
  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description createSessionData SessionData the metadata used to create the Leapp Session"},{"location":"plugins/plugins-development/#clonesession","title":"cloneSession","text":"
  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description session Session the Leapp Session that I want to clone"},{"location":"plugins/plugins-development/#updatesession","title":"updateSession","text":"
  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description updateSessionData SessionData the metadata used to update the given Leapp Session session Session the Leapp Session that I want to update"},{"location":"plugins/plugins-development/#openterminal","title":"openTerminal","text":"
  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description command string the command that I want to execute in the platform-specific terminal env any optional key/value env variables object"},{"location":"plugins/plugins-development/#getprofileidbyname","title":"getProfileIdByName","text":"
  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description profileName string a valid named profile"},{"location":"plugins/plugins-development/#getidpurlidbyurl","title":"getIdpUrlIdByUrl","text":"
  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description url string the URL associated with the IdpUrl I want to retrieve"},{"location":"plugins/plugins-development/#example-display-a-toast-message-in-leapp","title":"Example: display a toast message in Leapp","text":"
this.pluginEnvironment.log(\"Hello World\", LogLevel.info, true);\n
"},{"location":"plugins/plugins-development/#example-fetch-basic-usage","title":"Example: fetch basic usage","text":"
const res = await this.pluginEnvironment.fetch(\"\"); //Insert a custom URL\nconst response = await res.json();\n
"},{"location":"plugins/plugins-development/#example-open-a-url-in-the-browser","title":"Example: open a URL in the browser","text":"
this.pluginEnvironment.openExternalUrl(\"https://leapp.cloud\");\n
"},{"location":"plugins/plugins-development/#example-create-a-session","title":"Example: create a session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n\n    this.pluginEnvironment.createSession(new AwsIamRoleFederatedSessionData(\n      \"arn:aws:iam::000000000000:saml-provider/test\",\n      idpUrlId,\n      profileId,\n      \"us-east-1\",\n      \"arn:aws:iam::000000000000:role/test\",\n      \"New Name Session\"\n    ));\n}\n
"},{"location":"plugins/plugins-development/#example-edit-the-selected-session","title":"Example: edit the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n    this\n    .pluginEnvironment.updateSession(new AwsIamRoleFederatedSessionData(\n        \"arn:aws:iam::000000000000:saml-provider/test\", \n        idpUrlId, \n        profileId, \n        \"us-east-1\", \n        \"arn:aws:iam::000000000000:role/test\", \n        \"New Name Session\"\n    ), session);\n}\n
"},{"location":"plugins/plugins-development/#example-clone-the-selected-session","title":"Example: clone the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    await this.pluginEnvironment.cloneSession(session);\n}\n
"},{"location":"plugins/plugins-development/#awscredentialsplugin","title":"AwsCredentialsPlugin","text":"

A base class that needs to be extended by a plugin and serves as the action class.

After extending this class, you need to implement these methods:

"},{"location":"plugins/plugins-development/#applysessionaction","title":"applySessionAction","text":"
  • applySessionAction(session: Session, credentials: any): Promise<void>

Run your custom action

argument type description session Session the Leapp session you run the action from credentials any Leapp temporary-generated credentials

The credentials object has the following structure:

export interface CredentialsInfo {\n  sessionToken: {\n    aws_access_key_id: string;\n    aws_secret_access_key: string;\n    aws_session_token: string;\n    region: string;\n  }\n}\n
"},{"location":"plugins/plugins-development/#get-actioname","title":"get actioName","text":"
  • get actionName(): string>

Return a name for the action that will be display in Leapp (e.g. \"My Awesome Plugin\")

"},{"location":"plugins/plugins-development/#get-actionicon","title":"get actionIcon","text":"
  • get actionIcon(): string

Return a valid FontAwesome 5 code. Override default value in package.json

"},{"location":"plugins/plugins-development/#example-display-a-session-based-message-in-leapp","title":"Example: display a session-based message in Leapp","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    if(session.type === Session.awsIamUser) {\n        this.pluginEnvironment.log(`This is an IAM User session: ${session.sessionName}`, LogLevel.info, true); \n    }\n    else {\n        this.pluginEnvironment.log(`This is NOT an IAM User session: ${session.sessionName}`, LogLevel.info, true);\n    }\n}\n
"},{"location":"plugins/plugins-development/#packagejson-metadata","title":"package.json metadata","text":"property values description constraints name a custom string the name of the plugin the same used in the plugin folder author a custom string the name of the author none version a custom string the version of the plugin must be a semver string description a custom string the description of the plugin none keywords a string array the name of the plugin must contain at least \"leapp-plugin\" leappPlugin an object the plugin custom configuration must contain at least \"supportedOS\" and \"supportedSessions\" leappPlugin.supportedOS a string array [\"mac\", \"windows\", \"linux\"] if not specified, all OSs will be considered compatible leappPlugin.supportedSessions a string array [\"anyType, \"aws\", \"azure\", \"awsIamRoleFederated\", \"awsIamRoleChained\", \"awsSsoRole\", \"awsIamUser\"] at least one of these values must be specified leappPlugin.icon a custom string fontAwesome code for an icon (e.g. \"fa fa-globe\") must be a valid FontAwesome 5 code"},{"location":"plugins/plugins-development/#plugin-examples","title":"Plugin Examples","text":""},{"location":"plugins/plugins-development/#open-web-console","title":"Open Web Console","text":"
import { Session } from \"@noovolari/leapp-core/models/session\";\nimport { AwsCredentialsPlugin } from \"@noovolari/leapp-core/plugin-sdk/aws-credentials-plugin\";\nimport { PluginLogLevel } from \"@noovolari/leapp-core/plugin-sdk/plugin-log-level\";\n\nexport class WebConsolePlugin extends AwsCredentialsPlugin {\n  get actionName(): string {\n    return \"Open web console\";\n  }\n\n  get actionIcon(): string {\n    return \"fa fa-globe\";\n  }\n\n  async applySessionAction(session: Session, credentials: any): Promise<void> {\n    this.pluginEnvironment.log(\"Opening web console for session: \" + session.sessionName, PluginLogLevel.info, true);\n\n    const sessionRegion = session.region;\n    const sessionDuration = 3200;\n    const isUSGovCloud = sessionRegion.startsWith(\"us-gov-\");\n    let federationUrl;\n    let consoleHomeURL;\n\n    if (!isUSGovCloud) {\n      federationUrl = \"https://signin.aws.amazon.com/federation\";\n      consoleHomeURL = `https://${sessionRegion}.console.aws.amazon.com/console/home?region=${sessionRegion}`;\n    } else {\n      federationUrl = \"https://signin.amazonaws-us-gov.com/federation\";\n      consoleHomeURL = `https://console.amazonaws-us-gov.com/console/home?region=${sessionRegion}`;\n    }\n\n    if (sessionRegion.startsWith(\"cn-\")) {\n      throw new Error(\"Unsupported Region\");\n    }\n\n    this.pluginEnvironment.log(\"Starting opening Web Console\", PluginLogLevel.info, true);\n\n    const sessionStringJSON = {\n      sessionId: credentials.sessionToken.aws_access_key_id,\n      sessionKey: credentials.sessionToken.aws_secret_access_key,\n      sessionToken: credentials.sessionToken.aws_session_token,\n    };\n\n    const queryParametersSigninToken = `?Action=getSigninToken&SessionDuration=${sessionDuration}&Session=${encodeURIComponent(\n      JSON.stringify(sessionStringJSON)\n    )}`;\n\n    const res = await this.pluginEnvironment.fetch(`${federationUrl}${queryParametersSigninToken}`);\n    const response = await res.json();\n\n    const loginURL = `${federationUrl}?Action=login&Issuer=Leapp&Destination=${consoleHomeURL}&SigninToken=${(response as any).SigninToken}`;\n    this.pluginEnvironment.openExternalUrl(loginURL);\n  }\n}\n
"},{"location":"plugins/plugins-introduction/","title":"Introduction to Plugins","text":"

This section provides an overview of Leapp\u2019s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

"},{"location":"plugins/plugins-introduction/#add-a-plugin","title":"Add a Plugin","text":"

To add a plugin you can use one of the following methods:

"},{"location":"plugins/plugins-introduction/#add-from-npm","title":"Add from npm","text":"

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

"},{"location":"plugins/plugins-introduction/#add-manually","title":"Add manually","text":"

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

"},{"location":"plugins/plugins-introduction/#disable-a-plugin","title":"Disable a Plugin","text":"

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

"},{"location":"plugins/plugins-introduction/#remove-a-plugin","title":"Remove a Plugin","text":"

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

"},{"location":"plugins/plugins-introduction/#run-a-plugin","title":"Run a Plugin","text":"

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

"},{"location":"plugins/plugins-introduction/#plugin-menu","title":"Plugin Menu","text":"

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

"},{"location":"plugins/plugins-introduction/#create-your-plugin","title":"Create your Plugin","text":"

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             \n \u251c\u2500\u2500 package.json      # Plugin metadata\n \u2514\u2500\u2500 plugin.js         # A webpack bundle for the main logic\n

Create your Plugin

"},{"location":"security/credential-process/","title":"Credential Process","text":""},{"location":"security/credential-process/#what-is-credential-process","title":"What is Credential Process?","text":"

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the \"credential file\" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

"},{"location":"security/credential-process/#how-credential-process-works","title":"How Credential Process works?","text":"

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{\n  \"Version\": 1,\n  \"AccessKeyId\": \"an AWS access key\",\n  \"SecretAccessKey\": \"your AWS secret access key\",\n  \"SessionToken\": \"the AWS session token for temporary credentials\", \n  \"Expiration\": \"ISO8601 timestamp when the credentials expire\"\n}  \n

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

"},{"location":"security/credential-process/#advantages","title":"Advantages","text":"
  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

"},{"location":"security/credential-process/#how-leapp-works-with-credential-process","title":"How Leapp works with Credential Process","text":"

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel ().

2) In the general section change the AWS Credential Generation from \"credential-file-method\" to \"credential-process-method\".

3) An informative panel will show up telling that you need the CLI installed (see below), click on \"I acknowledge it\"

warning modal

4) Now, everytime you click on start () an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]\ncredential_process=leapp session generate SESSION_ID\nregion=REGION\n

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

"},{"location":"security/intro/","title":"Intro","text":"

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc. Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc."},{"location":"security/intro/#end-to-end-encryption","title":"End-to-end Encryption","text":"

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

"},{"location":"security/system-vault/","title":"System Vault","text":"

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

"},{"location":"security/system-vault/#supported-system-vaults","title":"Supported System Vaults","text":"OS System Vault MacOS Keychain Windows Credential Vault Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

"},{"location":"security/zero-knowledge/","title":"Zero Knowledge","text":"

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

"},{"location":"security/zero-knowledge/#users-have-key-control","title":"Users have key control","text":"

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

"},{"location":"security/zero-knowledge/#criteria","title":"Criteria","text":"
  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.
"},{"location":"security/zero-knowledge/#technologies","title":"Technologies","text":"
  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
"},{"location":"security/credentials-generation/aws/","title":"Credential file","text":"

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

"},{"location":"security/credentials-generation/aws/#iam-federated-role","title":"IAM Federated Role","text":""},{"location":"security/credentials-generation/aws/#assumerolewithsaml","title":"assumeRoleWithSAML","text":"

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

\u26a0\ufe0f In this case, generated credentials are not \"cached\" in the keychain.

"},{"location":"security/credentials-generation/aws/#iam-chained-role","title":"IAM Chained Role","text":"

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

"},{"location":"security/credentials-generation/aws/#iam-user","title":"IAM User","text":"

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

"},{"location":"security/credentials-generation/aws/#aws-sso-role","title":"AWS SSO Role","text":"

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

"},{"location":"security/credentials-generation/azure/","title":"Azure","text":""},{"location":"security/credentials-generation/azure/#azure-credentials-generation","title":"Azure credentials generation","text":"

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API. Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

"},{"location":"security/credentials-generation/azure/#access-strategy-login-integration","title":"Access strategy - login integration","text":"

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.
"},{"location":"security/credentials-generation/azure/#access-strategy-start-session","title":"Access strategy - start session","text":"

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source
"},{"location":"security/credentials-generation/azure/#access-strategy-rotate-session","title":"Access strategy - rotate session","text":"

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.
"},{"location":"security/credentials-generation/azure/#access-strategy-stop-session","title":"Access strategy - stop session","text":"

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

"},{"location":"troubleshooting/app-data/","title":"Application Data","text":""},{"location":"troubleshooting/app-data/#default-leapp-directories","title":"Default Leapp directories","text":"

Here the user can find all the directories that Leapp uses directly or indirectly.

"},{"location":"troubleshooting/app-data/#installation-path","title":"Installation path","text":"

By default, Leapp is installed in the following locations:

MacOSLinuxWindows
/Applications\n
/opt/Leapp\n
C:\\Users\\<USER>\\AppData\\Local\\Programs\\Leapp\n
"},{"location":"troubleshooting/app-data/#configuration-files","title":"Configuration files","text":"

By default, Leapp stores the configuration files in the following locations:

MacOSLinuxWindows
~/.Leapp\n
~/.Leapp\n
C:\\Users\\<USER>\\.Leapp\n

Info

  • Leapp-lock.json stores the Leapp configuration and is encrypted.
    • On startup, if Leapp-lock.json is not found, Leapp will create an empty version of it.
  • Leapp-lock.backup.bin stores a backup of Leapp-lock.json and is updated on startup if Leapp-lock.json is considered valid.
    • On startup, if Leapp-lock.json is corrupted, Leapp-lock.backup.bin will be used to restore it.
    • If both files are corrupted, a new empty configuration will be created.
  • .latest contains the latest version number of Leapp. If missing, it will be created again on startup.
"},{"location":"troubleshooting/app-data/#credentials-file","title":"Credentials file","text":"

By default, Leapp writes the credentials file in the following locations:

MacOSLinuxWindows
~/.aws\n
~/.aws\n
C:\\Users\\<USER>\\.aws\n
"},{"location":"troubleshooting/app-data/#logs-file","title":"Logs file","text":"

By default, Leapp writes logs to the following locations:

MacOSLinuxWindows
~/Library/Logs/Leapp/log.electronService.log\n
~/.config/Leapp/logs/log.electronService.log\n
C:\\Users\\<USER>\\AppData\\Roaming\\Leapp\\log.electronService.log\n

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}\n

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

"},{"location":"troubleshooting/faq/","title":"FAQ","text":""},{"location":"troubleshooting/faq/#im-using-the-open-source-app-do-you-store-my-data-online","title":"I'm using the open-source app, do you store my data online?","text":"

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

"},{"location":"troubleshooting/faq/#ive-got-a-paid-tier-how-do-you-manage-my-data-can-you-access-it","title":"I've got a paid tier, how do you manage my data? Can you access it?","text":"

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

"},{"location":"troubleshooting/faq/#i-dont-feel-secure-using-a-built-in-window-for-authentication-cant-you-use-the-default-browser","title":"I don't feel secure using a built-in window for authentication, can't you use the default browser?","text":"

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

"},{"location":"troubleshooting/faq/#how-can-i-find-leapp-data-in-the-system-vault","title":"How can I find Leapp data in the System Vault?","text":"

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

"},{"location":"troubleshooting/faq/#where-do-i-find-the-leapp-logs","title":"Where do I find the Leapp logs?","text":"

Head to the Application data section.

"},{"location":"troubleshooting/faq/#ssm-terminal-is-opening-but-no-session-is-starting-what-can-i-do","title":"SSM terminal is opening but no session is starting, what can I do?","text":"

Just close the terminal and relaunch the SSM command.

"},{"location":"troubleshooting/faq/#aws-cli-or-az-cli-is-installed-but-leapp-cant-find-it-what-can-i-do","title":"AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?","text":"

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws\nln -s /path/to/my/az /usr/local/bin/az\n
"},{"location":"troubleshooting/faq/#i-use-leapp-session-current-but-want-to-see-the-alias-and-not-the-id","title":"I use leapp session current but want to see the alias and not the id.","text":""},{"location":"troubleshooting/faq/#setting-up-leappalias-command","title":"Setting up leappalias command","text":"

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash\nleapp session current | grep -o \"\\\"alias\\\":\\\"[^\\\"]*\" | cut -d '\"' -f 4\n
  • Save the file and make it executable by running the following command in the terminal:
chmod +x leappalias.sh\n
  • Move the script to a directory in your system's PATH. For example, /usr/local/bin/:
sudo mv leappalias.sh /usr/local/bin/leappalias\n
  • Open your zshrc file using a text editor:
nano ~/.zshrc\n
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'\n
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc\n

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

"},{"location":"troubleshooting/faq/#how-can-i-add-support-to-a-new-saml-20-identity-provider","title":"How can I add support to a new SAML 2.0 Identity Provider?","text":"

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

"},{"location":"usefull-scripts/export-profile/","title":"Useful Scripts","text":""},{"location":"usefull-scripts/export-profile/#aws-profile-selector-simplifying-aws-profile-selection-with-the-leapp-cli","title":"AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI","text":"

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {\n    local selected_profile\n    selected_profile=$(leapp session list | \\\n        grep -w 'active' | \\\n        awk '{print $(NF-2)}' | \\\n        fzf --height 30% -1 -0 --header 'Select AWS profile')\n    if [[ -n \"$selected_profile\" ]]; then\n        export AWS_PROFILE=\"$selected_profile\"\n        echo \"AWS_PROFILE=$AWS_PROFILE\"\n    fi\n}\n\nalias awsp=select_and_export_aws_profile\n

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Overview","text":""},{"location":"#overview","title":"Overview","text":""},{"location":"#welcome-to-leapp","title":"Welcome to Leapp","text":"

Leapp is a tool for developers to manage, secure, and access the cloud.

All data is persisted and encrypted on your workstation. Head to our Security section to know how we guarantee the highest level of security.

Leapp Main Window

The name Leapp is based on the word leap and is pronounced /l:ip/. We chose this name because the project enables you to be one step away from your cloud environments.

"},{"location":"#introducing-leapp-cli","title":"Introducing Leapp CLI","text":"

Leapp CLI (Command Line Interface) for Leapp is built on Node.js with Oclif and the leapp core library.

You can follow the installation guidelines in order to make it work!

It allows you to use Leapp application functionality in your terminal.

Leapp CLI is open source on GitHub.

"},{"location":"configuration/","title":"Add your first configuration","text":"

Now it's time to add your very first configuration. Follow the link to your preferred supported method and start enjoying Leapp.

"},{"location":"configuration/#sessions","title":"Sessions","text":""},{"location":"configuration/#aws","title":"AWS","text":"

Select the configuration you need from the Access Method dropdown menu:

Leapp Iam User

Then follow the links below.

  • Configure an AWS IAM User
  • Configure an AWS IAM Role Federated
  • Configure an AWS IAM Role Chained
  • Configure LocalStack
"},{"location":"configuration/#integrations","title":"Integrations","text":""},{"location":"configuration/#aws-sso","title":"AWS SSO","text":"
  • Configure AWS SSO
"},{"location":"configuration/#azure-ad","title":"Azure AD","text":"
  • Configure an Azure Tenant
"},{"location":"edit-session/","title":"Editing a session","text":"

Leapp allows the user to edit an existing session excluding those generated from an AWS integration.

Info

Integration derived Sessions can\u2019t be changed

To edit an existing session just right-click on a session in the Leapp list (see below), and select \"edit session\". A new modal will appear, allowing the user to choose which parameters to change.

edit session

Below are the configuration options for every type of session:

"},{"location":"edit-session/#iam-user","title":"Iam User","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Mfa Device (optional): can be left empty or, if you add a valid device name or AWS ARN, it will prompt a modal for MFA code
  • Access Key ID: Replace your session Access Key ID in the system vault
  • Secret Access Key: Replace your session Secret Access Key in the system vault
"},{"location":"edit-session/#iam-role-chained","title":"IAM Role Chained","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: The role that you'll assume when chaining from an assumer window
  • Role Session Name: (optional), it will be used to identify the chained session
  • Assumer Session: select a session from the list, it will be the Principal assuming the role

Info

You can also generate a new IAM Role Chained session from any other AWS session by right-clicking on a session and chosing \"Create Chained Session\"

"},{"location":"edit-session/#iam-role-federated","title":"IAM Role Federated","text":"
  • Session Alias: the session name can be changed, as a session is identified by a hidden id
  • Named Profile: you can change a named profile and the session, if active, will restart itself
  • AWS Region: you can change the region and the session will restart itself, if active
  • Role ARN: Role of the Principal in AWS
  • SAML 2.0 Url: Federated URL needed for authentication to AWS
  • Identity Provider: the identity provider ARN that you have set up on AWS

After modifying all the parameters, a user can test their validity with test credential generation:

Clicking this button allows Leapp to do a dry run on your parameters, and if valid, a new set of credentials will be generated (but not used) and an informative toast will appear to tell you that they can be used successfully.

"},{"location":"edit-session/#how-we-handle-secrets-when-editing-a-session","title":"How we handle Secrets when Editing a Session","text":"

No secrets will be saved in plain text on your machine. Leapp saves secrets by replacing values in the system keychain, using a combination of an informative name plus the session hidden id.

This way we reduce potential blast radius of an attacker tampering your machine.

When editing a session, Leapp will hide your secrets and you are also unable to copy/paste them from the App.

"},{"location":"integrations/","title":"Integrations","text":"

This section provides an overview of Leapp's integrations, useful to extend the functionality of Leapp to 3rd party services.

Integrations help manage access and identities on your service of choice while using Leapp during your daily activities. They are automatically mapped into Sessions.

"},{"location":"integrations/#actions","title":"Actions","text":"

Integrations have four main actions available: Create, Delete, Sync, and Logout.

Action Description CREATE Configure a new Integration with the data needed to start the authentication flow. Required to Sync and map the service response into Sessions. DELETE Remove an existing Integration. Removes all the associated Sessions as well and wipes everything related to the Integration from the system (tokens, cache, etc.) SYNC Start the authentication flow to log into the Integration Provider. Leapp will automatically retrieve all the related data and map the response into Sessions. Any change in your service of choice requires a manual Sync to reflect the current status. LOGOUT Disable the Integration. Removes all the Sessions but keeps the Integration data. Running a Sync will restore all the Sessions tied to it."},{"location":"integrations/#supported-services","title":"Supported Services","text":"Service Supported AWS SSO Okta Coming Soon OneLogin Coming Soon AzureAD"},{"location":"sessions/","title":"Sessions","text":""},{"location":"sessions/#sessions","title":"Sessions","text":"

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

"},{"location":"sessions/#actions","title":"Actions","text":"Method Description START \u00a0Make the temporary credentials available to the provider chain STOP \u00a0Removes the temporary credentials from the provider chain ROTATE \u00a0Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

"},{"location":"workspaces/","title":"Workspaces","text":""},{"location":"workspaces/#workspaces","title":"Workspaces","text":"

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

"},{"location":"workspaces/#local","title":"Local","text":"

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

"},{"location":"workspaces/#remote","title":"Remote","text":"

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

"},{"location":"workspaces/#actions","title":"Actions","text":"

The actions below only applies to Remote workspaces.

Action Description Sign-in \u00a0Connect to a Remote workspace. This action will not switch your Local workspace Switch \u00a0Switch to the selected workspace by clicking on its name in the workspace menu Lock \u00a0Switch back to the Local workspace disabling all the Remote ones Sign-out \u00a0Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

"},{"location":"built-in-features/aws-ec2-connect/","title":"Configure AWS EC2 Connect","text":""},{"location":"built-in-features/aws-ec2-connect/#what-is-aws-ec2-connect","title":"What is AWS EC2 Connect","text":"

Amazon EC2 Instance Connect is a simple and secure way to connect to your instances using Secure Shell (SSH). With EC2 Instance Connect, you can control SSH access to your instances using AWS Identity and Access Management (IAM) policies as well as audit connection requests with AWS CloudTrail events.

"},{"location":"built-in-features/aws-ec2-connect/#how-to-configure-aws-ec2-connect-in-leapp","title":"How To configure AWS EC2 Connect in Leapp","text":"

Warning

If your Leapp Desktop App is warning you that you're missing the AWS Session Manager Plugin, please install it following this official guide.

You can directly connect to an AWS EC2 instance from Leapp through AWS System Manager (AWS SSM).

Info

To setup SSM follow this SSM guide on AWS guide.

example image from AWS

To correctly connect follow these steps:

  1. Right-click on a suitable AWS session to open the contextual menu.
  2. Click on View SSM sessions.
  3. Select the AWS region in which your instance is located.
  4. Wait for Leapp to load your instances.
  5. Select the instance and click connect.
  6. Wait for the terminal to open.
  7. Focus the terminal window and write /bin/bash; press Enter and you'll be inside the terminal of your instance.
"},{"location":"built-in-features/aws-ec2-connect/#video-tutorial","title":"Video tutorial","text":"

Warning

If the user is not granted the right permissions, the operation will fail and Leapp will throw an error message.

"},{"location":"built-in-features/aws-named-profiles/","title":"Configure Named Profiles","text":""},{"location":"built-in-features/aws-named-profiles/#what-is-a-named-profile","title":"What is a Named Profile","text":"

Named Profiles are used by AWS to maintain more than one set of active credentials for you to use with AWS-CLI, SDK, or other third-party tools. Named profiles are stored in ~/.aws/credentials file in the ini file format.

Named Profiles have a default profile which is the one you get from aws configure command.

With Leapp you can group and activate more than one credential set at a time through Named Profiles.

"},{"location":"built-in-features/aws-named-profiles/#how-to-configure-a-named-profile-in-leapp","title":"How to configure a Named Profile in Leapp","text":"

Named Profiles can be created in 3 ways:

Option PanelWhen creating a new SessionEdit Profile in Contextual Menu

Click on the gear icon and select the Profiles tab. Insert the name of the new Named Profile in the input form, then click on the plus icon.

When creating a new session, the user will have the option to choose a Named Profile or add a new one.

Right-click on a session and select Change then Named Profile: an option to select or add a new Named Profile will be available.

The new name is directly added to the Named Profile list and can then be used for other sessions too.

Info

AWS SSO sessions will have the Named Profile default when obtained via Login or Sync. To change the Named Profile associated to a session you have to use the \"Change Profile\" option in the session list.

"},{"location":"built-in-features/aws-named-profiles/#named-profile-list","title":"Named Profile List","text":"

Named profiles can be managed from the Option menu.

In the Option menu, under the Profiles tab, you can add or edit a new Named Profile, and you can also remove unwanted ones. When removing a Named Profile, Leapp will warn you about which sessions are using that profile, and those sessions will be reverted to the default Named Profile.

The input form can be used to add or edit a Named Profile: if it's empty, you can use it to add a new named profile. When selecting the button, you will be able to edit the name of the Named Profile from within the input form.

Warning

Remember that when you change the profile of a session, the session will be immediately put in stop mode. That's because Leapp would have to change the credential file, so you will need to restart the session again.

"},{"location":"built-in-features/general-options/","title":"General Options","text":"

Once you've opened the Leapp option menu - which can be accessed by clicking the top right gear icon - you can edit the following settings in the General tab

"},{"location":"built-in-features/general-options/#default-regions","title":"Default Regions","text":"

This option allows you to set the default AWS or Azure region/location for every new session.

Each time you create a new session, this will be the default region assigned to it.

You can still change it if you need a different one, by selecting a different region while creating the session or by changing the region once a session is created.

"},{"location":"built-in-features/general-options/#terminal-selection","title":"Terminal Selection","text":"

This option is used to select the terminal in which to open an SSM session.

Info

This setting is currently only available on MacOS. If you want to contribute and add a new terminal for a specific OS, please refer to the contributing guide

"},{"location":"built-in-features/general-options/#color-theme","title":"Color Theme","text":"

Leapp now comes with a slick new Dark Theme!

With this option, you can switch between light and dark theme, or use your system default.

"},{"location":"built-in-features/general-options/#default-webconsole-duration","title":"Default Webconsole Duration","text":"

This option is used to set the default Webconsole session duration in hours.

Info

The minimum session duration is 1 hour, and can be set to a maximum of 12 hours. Set session duration

"},{"location":"built-in-features/multi-console/","title":"Configure Multi Console","text":""},{"location":"built-in-features/multi-console/#what-is-multi-console","title":"What is Multi Console","text":"

The Leapp Multi-Console Browser Extension allows you to open multiple instances of the AWS Web Console in the same browser window and helps you in managing them.

Get it on Firefox \u21e9 Get it on Chrome \u21e9"},{"location":"built-in-features/multi-console/#list-of-supported-browsers","title":"List of Supported Browsers","text":"Browser Supported Firefox Chrome Edge Brave Safari"},{"location":"built-in-features/multi-console/#how-to-configure-multi-console-in-leapp","title":"How to Configure Multi Console in Leapp","text":""},{"location":"built-in-features/multi-console/#install-the-extension","title":"Install the Extension","text":""},{"location":"built-in-features/multi-console/#firefox","title":"Firefox","text":"

You can get the extension on the official Mozilla Addons Store and install it from there:

  1. Visit the page by clicking the button below
  2. Then Click on Add to Firefox

Get it on Firefox \u21e9

"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers","title":"Chrome, Edge and other Chromium based browsers","text":"

Info

Because the extension at the moment relies on Manifest V2, we are unable to upload the extension on the official stores. For more info see Chrome extension documentation

The extension can only be installed manually. To do so, follow these instructions:

  1. Download the zip archive by clicking on the button below
  2. Unzip the file
  3. Open your browser and navigate to about://extensions
  4. Enable Developer mode in the top right corner
  5. Then click on Load unpacked in the top left corner
  6. Finally, Select the folder extracted previously

Get it on Chrome/Others \u21e9

"},{"location":"built-in-features/multi-console/#uninstall-the-extension","title":"Uninstall the Extension","text":""},{"location":"built-in-features/multi-console/#firefox_1","title":"Firefox","text":"
  1. Visit about:addons
  2. Select Leapp Browser Extension and click on the 3 dots
  3. Click on Remove
"},{"location":"built-in-features/multi-console/#chrome-edge-and-other-chromium-based-browsers_1","title":"Chrome, Edge and other Chromium based browsers","text":"
  1. Visit about://extensions
  2. Search for Leapp Browser Extension and click on Remove
  3. See warning section below

Warning

If you are using the Chrome version and you uninstalled or disabled the extension, you have to manually clear cookies for the AWS Console. To do so, when accessing the login page of the AWS Console, on the left of the address bar, click the lock icon and select \"Cookies\". Then, remove all cookies by clicking \"Remove\" until the cookie list is empty and finally click on Done

"},{"location":"built-in-features/multi-console/#how-to-use-it","title":"How to use it","text":"

Once you've installed the extension on your browser, you need to enable the Multi-Console Extension on the Leapp Desktop App in order to use it.

Click on the top-right cog icon to access the settings, click on the Multi-Console tab and then click Enable Multi-Console Extension.

enable option

From the contextual menu of a session (accessed by right-clicking on it), simply select Open Web Console.

Info

If any communication error occurs, your browser is not open or you don't have the extension installed/enabled on it, the web console will be opened in your default browser without using the extension (and will be limited to a single session).

By clicking on the Leapp Multi-Console Extension icon in your browser, a list of all currently active sessions will be shown.

This list contains information obtained from Leapp about the session, including Session Name, Session Role and Session Region.

leapp browser ui

In the extension interface, click on a row to select and focus the tab in which you opened the related AWS Console, so you can easily navigate among many AWS Consoles at the same time.

"},{"location":"built-in-features/opening-web-console/","title":"Configure Open Web Console","text":""},{"location":"built-in-features/opening-web-console/#what-is-open-web-console","title":"What is Open Web Console","text":"

Open Web Console is a Leapp feature that allows you to open the AWS Web Console of a session that you've created in Leapp.

"},{"location":"built-in-features/opening-web-console/#how-to-configure-open-web-console-in-leapp","title":"How to Configure Open Web Console in Leapp","text":"

You can open the AWS Web Console directly from Leapp, without having to log in, input your credentials, or select the role to assume.

To do that just right-click or select the session you want to open in the web console, and click on the icon either in the context-menu or in the bottom-bar below.

Alternatively, you can Command + left-click on a session (or Control + left-click for Windows/Linux ) to open the web console.

Leapp will open your default browser with the Region and the Role already prepared for you in the account you've selected.

note: to use this feature correctly, remember to logout from any web console already opened in the browser.

note: the feature currently is available for IAM Role Federated Sessions, Single Sign-On Sessions, and IAM Role Chained Sessions.

"},{"location":"cli/","title":"Index","text":"

Leapp's Command Line Interface.

Warning

Leapp CLI works only if the Desktop App is installed and running. Note that version >= v0.11.0 of the Desktop App is required. Check the installation guide to install the Desktop App.

$ npm install -g @noovolari/leapp-cli\n$ leapp COMMAND\nrunning command...\n$ leapp (--version)\n@noovolari/leapp-cli/0.1.65 darwin-x64 node-v21.6.2\n$ leapp --help [COMMAND]\nUSAGE\n  $ leapp COMMAND\n...\n
"},{"location":"cli/#command-topics","title":"Command Topics","text":"
  • leapp help - Display help for leapp.
  • leapp idp-url - SAML 2.0 Identity providers URL management
  • leapp integration - Leapp Integrations management
  • leapp profile - Leapp AWS Multi-profile management
  • leapp region - Leapp regions management
  • leapp session - Sessions management
  • leapp set-workspace - Set the current Leapp workspace
  • leapp team - Login to your Team account
  • leapp version - Displays the Cli and Core versions
  • leapp workspace - Show the current workspace
"},{"location":"cli/scopes/help/","title":"Help","text":""},{"location":"cli/scopes/help/#leapp-help","title":"leapp help","text":"

Display help for leapp.

  • leapp help [COMMANDS]
"},{"location":"cli/scopes/help/#leapp-help-commands","title":"leapp help [COMMANDS]","text":"

Display help for leapp.

USAGE\n  $ leapp help [COMMANDS] [-n]\n\nARGUMENTS\n  COMMANDS  Command to show help for.\n\nFLAGS\n  -n, --nested-commands  Include all nested commands in the output.\n\nDESCRIPTION\n  Display help for leapp.\n

See code: @oclif/plugin-help

"},{"location":"cli/scopes/idp-url/","title":"Idp Url","text":""},{"location":"cli/scopes/idp-url/#leapp-idp-url","title":"leapp idp-url","text":"

SAML 2.0 Identity providers URL management

  • leapp idp-url create
  • leapp idp-url delete
  • leapp idp-url edit
  • leapp idp-url list
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-create","title":"leapp idp-url create","text":"

Create a new identity provider URL

USAGE\n  $ leapp idp-url create [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>  the idp url address we want to create\n\nDESCRIPTION\n  Create a new identity provider URL\n\nEXAMPLES\n  $leapp idp-url create\n\n  $leapp idp-url create --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-delete","title":"leapp idp-url delete","text":"

Delete an identity provider URL

USAGE\n  $ leapp idp-url delete [--idpUrlId <value>] [-f]\n\nFLAGS\n  -f, --force         force a command without asking for confirmation (-f, --force)\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Delete an identity provider URL\n\nEXAMPLES\n  $leapp idp-url delete\n\n  $leapp idp-url delete --idpUrlId ID\n\n  $leapp idp-url delete --idpUrlId ID [--force, -f]\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-edit","title":"leapp idp-url edit","text":"

Edit an identity provider URL

USAGE\n  $ leapp idp-url edit [--idpUrlId <value>] [--idpUrl <value>]\n\nFLAGS\n  --idpUrl=<value>    the idp url address we want to create\n  --idpUrlId=<value>  the idp url id that we want to pass to the function like the delete one\n\nDESCRIPTION\n  Edit an identity provider URL\n\nEXAMPLES\n  $leapp idp-url edit\n\n  $leapp idp-url edit --idpUrlId ID --idpUrl ADDRESS\n
"},{"location":"cli/scopes/idp-url/#leapp-idp-url-list","title":"leapp idp-url list","text":"

Show identity providers list

USAGE\n  $ leapp idp-url list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show identity providers list\n\nEXAMPLES\n  $leapp idp-url list\n
"},{"location":"cli/scopes/integration/","title":"Integration","text":""},{"location":"cli/scopes/integration/#leapp-integration","title":"leapp integration","text":"

Leapp Integrations management

  • leapp integration create
  • leapp integration delete
  • leapp integration list
  • leapp integration login
  • leapp integration logout
  • leapp integration sync
"},{"location":"cli/scopes/integration/#leapp-integration-create","title":"leapp integration create","text":"

Create a new integration

USAGE\n  $ leapp integration create [--integrationAlias <value>] [--integrationPortalUrl <value>] [--integrationRegion <value>]\n    [--integrationType AWS-SSO|AZURE] [--integrationTenantId <value>] [--integrationLocation <value>]\n\nFLAGS\n  --integrationAlias=<value>      alias that identifies an integration\n  --integrationLocation=<value>   Location of an Azure Integration\n  --integrationPortalUrl=<value>  url that identifies the integration portal where you authenticate\n  --integrationRegion=<value>     an AWS valid region code for the integration\n  --integrationTenantId=<value>   Tenant ID of an Azure Integration\n  --integrationType=<option>      Identify the type of your integration. Valid types are [AWS-SSO, AZURE]\n                                  <options: AWS-SSO|AZURE>\n\nDESCRIPTION\n  Create a new integration\n\nEXAMPLES\n  $leapp integration create\n\n  $leapp integration create --integrationType AWS-SSO --integrationAlias ALIAS --integrationPortalUrl URL --integrationRegion REGION\n\n  $leapp integration create --integrationType AZURE --integrationAlias ALIAS --integrationTenantId TENANT --integrationLocation LOCATION\n
"},{"location":"cli/scopes/integration/#leapp-integration-delete","title":"leapp integration delete","text":"

Delete an integration

USAGE\n  $ leapp integration delete [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Delete an integration\n\nEXAMPLES\n  $leapp integration delete\n\n  $leapp integration delete --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-list","title":"leapp integration list","text":"

Show integrations list

USAGE\n  $ leapp integration list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show integrations list\n\nEXAMPLES\n  $leapp integration list\n
"},{"location":"cli/scopes/integration/#leapp-integration-login","title":"leapp integration login","text":"

Login to synchronize integration sessions

USAGE\n  $ leapp integration login [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Login to synchronize integration sessions\n\nEXAMPLES\n  $leapp integration login\n\n  $leapp integration login --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-logout","title":"leapp integration logout","text":"

Logout from an integration

USAGE\n  $ leapp integration logout [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Logout from an integration\n\nEXAMPLES\n  $leapp integration logout\n\n  $leapp integration logout --integrationId ID\n
"},{"location":"cli/scopes/integration/#leapp-integration-sync","title":"leapp integration sync","text":"

Synchronize integration sessions

USAGE\n  $ leapp integration sync [--integrationId <value>]\n\nFLAGS\n  --integrationId=<value>  the Integration Id used to identify the integration inside Leapp\n\nDESCRIPTION\n  Synchronize integration sessions\n\nEXAMPLES\n  $leapp integration sync\n\n  $leapp integration sync --integrationId ID\n
"},{"location":"cli/scopes/profile/","title":"Profile","text":""},{"location":"cli/scopes/profile/#leapp-profile","title":"leapp profile","text":"

Leapp AWS Multi-profile management

  • leapp profile create
  • leapp profile delete
  • leapp profile edit
  • leapp profile list
"},{"location":"cli/scopes/profile/#leapp-profile-create","title":"leapp profile create","text":"

Create a new AWS named profile

USAGE\n  $ leapp profile create [--profileName <value>]\n\nFLAGS\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Create a new AWS named profile\n\nEXAMPLES\n  $leapp profile create\n\n  $leapp profile create --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-delete","title":"leapp profile delete","text":"

Delete an AWS named profile

USAGE\n  $ leapp profile delete [--profileId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --profileId=<value>  an AWS named profile ID in Leapp\n\nDESCRIPTION\n  Delete an AWS named profile\n\nEXAMPLES\n  $leapp profile delete\n\n  $leapp profile delete --profileId PROFILEID\n\n  $leapp profile delete --profileId PROFILEID [--force, -f]\n
"},{"location":"cli/scopes/profile/#leapp-profile-edit","title":"leapp profile edit","text":"

Rename an AWS named profile

USAGE\n  $ leapp profile edit [--profileId <value>] [--profileName <value>]\n\nFLAGS\n  --profileId=<value>    an AWS named profile ID in Leapp\n  --profileName=<value>  an AWS named profile Alias used to identify the profile in both config and credential file\n\nDESCRIPTION\n  Rename an AWS named profile\n\nEXAMPLES\n  $leapp profile edit\n\n  $leapp profile edit --profileId ID --profileName PROFILENAME\n
"},{"location":"cli/scopes/profile/#leapp-profile-list","title":"leapp profile list","text":"

Show profile list

USAGE\n  $ leapp profile list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show profile list\n\nEXAMPLES\n  $leapp profile list\n
"},{"location":"cli/scopes/region/","title":"Region","text":""},{"location":"cli/scopes/region/#leapp-region","title":"leapp region","text":"

Leapp regions management

  • leapp region get-default
  • leapp region set-default
"},{"location":"cli/scopes/region/#leapp-region-get-default","title":"leapp region get-default","text":"

Displays the default region

USAGE\n  $ leapp region get-default\n\nDESCRIPTION\n  Displays the default region\n\nEXAMPLES\n  $leapp region get-default\n
"},{"location":"cli/scopes/region/#leapp-region-set-default","title":"leapp region set-default","text":"

Change the default region

USAGE\n  $ leapp region set-default [--region <value>]\n\nFLAGS\n  --region=<value>  Session Region for AWS sessions in Leapp\n\nDESCRIPTION\n  Change the default region\n\nEXAMPLES\n  $leapp region set-default\n\n  $leapp region set-default --region AWSREGION\n
"},{"location":"cli/scopes/session/","title":"Session","text":""},{"location":"cli/scopes/session/#leapp-session","title":"leapp session","text":"

Sessions management

  • leapp session add
  • leapp session change-profile
  • leapp session change-region
  • leapp session current
  • leapp session delete
  • leapp session generate SESSIONID
  • leapp session get-id
  • leapp session list
  • leapp session open-web-console
  • leapp session run-aws-credential-plugin
  • leapp session start [SESSIONNAME]
  • leapp session start-ssm-session
  • leapp session stop [SESSIONNAME]
"},{"location":"cli/scopes/session/#leapp-session-add","title":"leapp session add","text":"

Add a new session

USAGE\n  $ leapp session add [--providerType aws] [--accessKey <value>] [--idpArn <value>] [--idpUrl <value>]\n    [--mfaDevice <value>] [--sessionName <value>] [--parentSessionId <value>] [--profileId <value>] [--region <value>]\n    [--roleArn <value>] [--roleSessionName <value>] [--secretKey <value>] [--sessionType\n    awsIamRoleFederated|awsIamUser|awsIamRoleChained]\n\nFLAGS\n  --accessKey=<value>        AWS Access Key ID of the IAM User\n  --idpArn=<value>           AWS IAM Federated Role IdP Arn value, obtain it from your AWS Account\n  --idpUrl=<value>           the idp url address we want to create\n  --mfaDevice=<value>        MFA Device Arn retrieved from your AWS Account\n  --parentSessionId=<value>  For AWS IAM Role Chained is the session Id of the session that will assume the chained\n                             role. Retrieve it using $leapp session list -x\n  --profileId=<value>        an AWS named profile ID in Leapp\n  --providerType=<option>    Identify the provider for your sessions. Valid types are [aws]\n                             <options: aws>\n  --region=<value>           Session Region for AWS sessions in Leapp\n  --roleArn=<value>          AWS IAM Federated Role Arn value, obtain it from your AWS Account\n  --roleSessionName=<value>  Optional Alias for the Assumed Role Session name\n  --secretKey=<value>        AWS Secret Access Key of the IAM User\n  --sessionName=<value>      Session Alias to identify the session in Leapp\n  --sessionType=<option>     Identify the AWS session type. Valid types are [awsIamRoleFederated, awsIamUser,\n                             awsIamRoleChained]\n                             <options: awsIamRoleFederated|awsIamUser|awsIamRoleChained>\n\nDESCRIPTION\n  Add a new session\n\nEXAMPLES\n  $leapp session add\n\n  $leapp session add --providerType [aws] --sessionType [awsIamRoleFederated, awsIamRoleChained, awsIamUser] --region [AWSREGION] --sessionName NAME ...[combination of flags relative to the session]\n\n  $leapp session add --providerType aws --sessionType awsIamRoleFederated --sessionName NAME --region AWSREGION --idpArn IDPARN --idpUrl IDPURL --profileId PROFILEID --roleArn ROLEARN\n\n  $leapp session add --providerType aws --sessionType awsIamRoleChained --sessionName NAME --region AWSREGION --profileId PROFILEID --roleArn ROLEARN --parentSessionId ID (--roleSessionName ROLESESSIONNAME)\n\n  $leapp session add --providerType aws --sessionType awsIamUser --sessionName NAME --region AWSREGION --profileId PROFILEID --accessKey ACCESSKEY --secretKey SECRETKEY (--mfaDevice MFADEVICEARN)\n
"},{"location":"cli/scopes/session/#leapp-session-change-profile","title":"leapp session change-profile","text":"

Change a session named-profile

USAGE\n  $ leapp session change-profile [--sessionId <value>] [--profileId <value>]\n\nFLAGS\n  --profileId=<value>  an AWS named profile ID in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session named-profile\n\nEXAMPLES\n  $leapp session change-profile\n\n  $leapp session change-profile --profileId PROFILEID --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-change-region","title":"leapp session change-region","text":"

Change a session region

USAGE\n  $ leapp session change-region [--sessionId <value>] [--region <value>]\n\nFLAGS\n  --region=<value>     Session Region for AWS sessions in Leapp\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Change a session region\n\nEXAMPLES\n  $leapp session change-region\n\n  $leapp session change-region --sessionId SESSIONID --region REGION\n
"},{"location":"cli/scopes/session/#leapp-session-current","title":"leapp session current","text":"

Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile default)

USAGE\n  $ leapp session current [-i] [-p <value>] [-r aws|azure] [-f <value>]\n\nFLAGS\n  -f, --format=<value>     allows formatting data to show\n                           - aws -> id alias, accountNumber, roleArn\n                           - azure -> id tenantId, subscriptionId\n  -i, --inline\n  -p, --profile=<value>    [default: default] aws named profile of which gets info\n  -r, --provider=<option>  filters sessions by the cloud provider service\n                           <options: aws|azure>\n\nDESCRIPTION\n  Provides info about the current active session for a selected profile (if no profile is provided, it uses the profile\n  default)\n\nEXAMPLES\n  $leapp session current --format \"alias accountNumber\" --inline --provider aws\n
"},{"location":"cli/scopes/session/#leapp-session-delete","title":"leapp session delete","text":"

Delete a session

USAGE\n  $ leapp session delete [--sessionId <value>] [-f]\n\nFLAGS\n  -f, --force          force a command without asking for confirmation (-f, --force)\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Delete a session\n\nEXAMPLES\n  $leapp session delete\n\n  $leapp session delete --sessionId SESSIONID\n\n  $leapp session delete --sessionId SESSIONID [--force, -f]\n
"},{"location":"cli/scopes/session/#leapp-session-generate-sessionid","title":"leapp session generate SESSIONID","text":"

Generate STS temporary credentials for the given AWS session id

USAGE\n  $ leapp session generate SESSIONID\n\nARGUMENTS\n  SESSIONID  id of the session\n\nDESCRIPTION\n  Generate STS temporary credentials for the given AWS session id\n\nEXAMPLES\n  $leapp session generate 0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d\n
"},{"location":"cli/scopes/session/#leapp-session-get-id","title":"leapp session get-id","text":"

Get session id

USAGE\n  $ leapp session get-id\n\nDESCRIPTION\n  Get session id\n\nEXAMPLES\n  $leapp session get-id\n
"},{"location":"cli/scopes/session/#leapp-session-list","title":"leapp session list","text":"

Show sessions list with all properties; filter query is case sensitive

USAGE\n  $ leapp session list [--columns <value> | -x] [--sort <value>] [--filter <value>] [--output csv|json|yaml |  |\n    [--csv | --no-truncate]] [--no-header | ]\n\nFLAGS\n  -x, --extended     show extra columns\n  --columns=<value>  only show provided columns (comma-separated)\n  --csv              output is csv format [alias: --output=csv]\n  --filter=<value>   filter property by partial string matching, ex: name=foo\n  --no-header        hide table header from output\n  --no-truncate      do not truncate output to fit screen\n  --output=<option>  output in a more machine friendly format\n                     <options: csv|json|yaml>\n  --sort=<value>     property to sort by (prepend '-' for descending)\n\nDESCRIPTION\n  Show sessions list with all properties; filter query is case sensitive\n\nEXAMPLES\n  $leapp session list\n\n  $leapp session list --filter=\"ID=Foo\" -x\n\n  $leapp session list --filter=\"Session Name=Foo\"\n\n  $leapp session list --filter=\"Type=Foo\"\n\n  $leapp session list --filter=\"Named Profile=Foo\"\n\n  $leapp session list --filter=\"Region/Location=Foo\"\n\n  $leapp session list --filter=\"Status=Foo\"\n
"},{"location":"cli/scopes/session/#leapp-session-open-web-console","title":"leapp session open-web-console","text":"

Open an AWS Web Console

USAGE\n  $ leapp session open-web-console [--sessionId <value>] [-p]\n\nFLAGS\n  -p, --print          Print an AWS Web Console login URL in the terminal instead of opening the web browser\n  --sessionId=<value>  Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Open an AWS Web Console\n\nEXAMPLES\n  $leapp session open-web-console\n\n  $leapp session open-web-console --sessionId SESSIONID [--print, -p]\n
"},{"location":"cli/scopes/session/#leapp-session-run-aws-credential-plugin","title":"leapp session run-aws-credential-plugin","text":"

Run a Leapp Plugin

USAGE\n  $ leapp session run-aws-credential-plugin [--sessionId <value>] [--pluginName <value>]\n\nFLAGS\n  --pluginName=<value>  Unique name of a Leapp Plugin\n  --sessionId=<value>   Session Id to identify the session in Leapp, recover it with $leapp session list -x\n\nDESCRIPTION\n  Run a Leapp Plugin\n\nEXAMPLES\n  $leapp session run-plugin\n\n  $leapp session run-plugin --sessionName SESSIONAME --pluginName PLUGINNAME\n
"},{"location":"cli/scopes/session/#leapp-session-start-sessionname","title":"leapp session start [SESSIONNAME]","text":"

Start a session

USAGE\n  $ leapp session start [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Start a session\n\nEXAMPLES\n  $leapp session start\n\n  $leapp session start SESSIONNAME\n\n  $leapp session start SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session start SESSIONNAME --noInteractive\n\n  $leapp session start --sessionId SESSIONID\n
"},{"location":"cli/scopes/session/#leapp-session-start-ssm-session","title":"leapp session start-ssm-session","text":"

Start an AWS SSM session

USAGE\n  $ leapp session start-ssm-session [--sessionId <value>] [--region <value>] [--ssmInstanceId <value>]\n\nFLAGS\n  --region=<value>         Session Region for AWS sessions in Leapp\n  --sessionId=<value>      Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --ssmInstanceId=<value>  Instance ID for EC2 instance we want to access with SSM\n\nDESCRIPTION\n  Start an AWS SSM session\n\nEXAMPLES\n  $leapp session start-ssm-session\n\n  $leapp session start-ssm-session --sessionId SESSIONID --region AWSREGION --ssmInstanceId EC2INSTANCEID\n
"},{"location":"cli/scopes/session/#leapp-session-stop-sessionname","title":"leapp session stop [SESSIONNAME]","text":"

Stop a session

USAGE\n  $ leapp session stop [SESSIONNAME] [--sessionId <value>] [--sessionRole <value>] [--noInteractive]\n\nARGUMENTS\n  SESSIONNAME  Name of the Leapp session\n\nFLAGS\n  --noInteractive        If the specified session is not unique or doesn't exist, throw an error without starting the\n                         interactive session selection mode\n  --sessionId=<value>    Session Id to identify the session in Leapp, recover it with $leapp session list -x\n  --sessionRole=<value>  Session Role of one or more sessions in Leapp\n\nDESCRIPTION\n  Stop a session\n\nEXAMPLES\n  $leapp session stop\n\n  $leapp session stop SESSIONNAME\n\n  $leapp session stop SESSIONNAME --sessionRole SESSIONROLE\n\n  $leapp session stop SESSIONNAME --noInteractive\n\n  $leapp session stop --sessionId SESSIONID\n
"},{"location":"cli/scopes/set-workspace/","title":"Set Workspace","text":""},{"location":"cli/scopes/set-workspace/#leapp-set-workspace","title":"leapp set-workspace","text":"

Set the current Leapp workspace

  • leapp set-workspace [WORKSPACENAME]
"},{"location":"cli/scopes/set-workspace/#leapp-set-workspace-workspacename","title":"leapp set-workspace [WORKSPACENAME]","text":"

Set the current Leapp workspace

USAGE\n  $ leapp set-workspace [WORKSPACENAME]\n\nARGUMENTS\n  WORKSPACENAME  name of the Leapp Team remote workspace or local\n\nDESCRIPTION\n  Set the current Leapp workspace\n\nEXAMPLES\n  $leapp team set-workspace\n\n  $leapp team set-workspace local\n\n  $leapp team set-workspace WORKSPACE-NAME\n

See code: dist/commands/set-workspace.ts

"},{"location":"cli/scopes/team/","title":"Team","text":""},{"location":"cli/scopes/team/#leapp-team","title":"leapp team","text":"

Login to your Team account

  • leapp team login
  • leapp team logout
  • leapp team status
"},{"location":"cli/scopes/team/#leapp-team-login","title":"leapp team login","text":"

Login to your Team account

USAGE\n  $ leapp team login\n\nDESCRIPTION\n  Login to your Team account\n\nEXAMPLES\n  $leapp team login\n
"},{"location":"cli/scopes/team/#leapp-team-logout","title":"leapp team logout","text":"

Logout from your Team account

USAGE\n  $ leapp team logout\n\nDESCRIPTION\n  Logout from your Team account\n\nEXAMPLES\n  $leapp team logout\n
"},{"location":"cli/scopes/team/#leapp-team-status","title":"leapp team status","text":"

Get the team login status

USAGE\n  $ leapp team status\n\nDESCRIPTION\n  Get the team login status\n\nEXAMPLES\n  $leapp team status\n
"},{"location":"cli/scopes/version/","title":"Version","text":""},{"location":"cli/scopes/version/#leapp-version","title":"leapp version","text":"

Displays the Cli and Core versions

  • leapp version
"},{"location":"cli/scopes/version/#leapp-version_1","title":"leapp version","text":"

Displays the Cli and Core versions

USAGE\n  $ leapp version\n\nDESCRIPTION\n  Displays the Cli and Core versions\n\nEXAMPLES\n  $leapp version\n

See code: dist/commands/version.ts

"},{"location":"cli/scopes/workspace/","title":"Workspace","text":""},{"location":"cli/scopes/workspace/#leapp-workspace","title":"leapp workspace","text":"

Show the current workspace

  • leapp workspace
"},{"location":"cli/scopes/workspace/#leapp-workspace_1","title":"leapp workspace","text":"

Show the current workspace

USAGE\n  $ leapp workspace\n\nDESCRIPTION\n  Show the current workspace\n\nEXAMPLES\n  $leapp workspace\n

See code: dist/commands/workspace.ts

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/","title":"Configure an AWS Identity Center (ex AWS Single Sign-On) integration","text":""},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#what-is-aws-identity-center-ex-aws-single-sign-on","title":"What is AWS Identity Center (ex AWS Single Sign-On)","text":"

AWS Identity Center (ex AWS Single Sign-On) is a cloud service that allows you to grant your users access to AWS resources across multiple AWS accounts.

AWS SSO provides a directory that you can use to create users, organize them in groups, and set permissions across those groups; alternatively, you can obtain them from your Microsoft Active Directory or any standards-based identity provider, such as Okta Universal Directory or Azure AD.

After logging in the first time, Leapp will map all your roles and users into Sessions.

Info

To get started using AWS SSO refer to this guide.

"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#how-to-configure-an-aws-identity-center-ex-aws-single-sign-on-integration-in-leapp","title":"How to configure an AWS Identity Center (ex AWS Single Sign-On) integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select AWS Single Sign-On as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as AWS Single Sign-on AWS SSO URL The portal URL to begin the authentication flow. It usually follows this pattern: d-xxxxxxxxxx.awsapps.com/start. REGION The region on which AWS SSO is administered and configured. This is NOT where your generated credentials will be valid; it's only used for the login part."},{"location":"configuring-integration/configure-aws-single-sign-on-integration/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-integration/configure-azure-integration/","title":"Configure an Azure integration","text":""},{"location":"configuring-integration/configure-azure-integration/#what-is-an-azure-integration","title":"What is an Azure integration","text":"

Our Leapp integration refers to Azure Tenant which is a dedicated and trusted instance of Azure AD.

The tenant is automatically created when your organization signs up for a Microsoft cloud service subscription.

These subscriptions include Microsoft Azure, Microsoft Intune, or Microsoft 365.

An Azure tenant represents a single organization and can have multiple subscriptions.

Please refer to How to find your Azure Active Directory tenant ID and other Azure AD documentation for more information.

Warning

For azure-cli users with version < 2.30.0: Leapp no longer supports this version of the CLI. Please update to a newer version.

To create a new Azure Integration, go to the left sidebar of Leapp Desktop and click on the icon. A new modal will be presented with the following option to compile. After submitting the new Integration and have logged into your Azure Portal, Subscriptions will be automatically retrieved and mapped into Leapp Azure Sessions.

"},{"location":"configuring-integration/configure-azure-integration/#how-to-configure-an-azure-integration-in-leapp","title":"How to configure an Azure integration in Leapp","text":"
  1. Click on the Add Integration button in the sidebar.
  2. Select Azure as the Integration type.
  3. Provide the required information (described in the next section).
  4. Click on the Add integration button.
"},{"location":"configuring-integration/configure-azure-integration/#required-information","title":"Required information","text":"Field Description INTEGRATION TYPE Set as Azure ALIAS Your friendly integration name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. TENANT ID A tenant ID identifies a tenant. You can have multiple clients on a given tenant database. LOCATION The Azure datacenters are located around the world in strategic places that best meet the customer demands. These areas are known as Azure locations. Specific services requires the user to select a specific location. The value is retrieved from your default location in general options."},{"location":"configuring-integration/configure-azure-integration/#video-tutorial","title":"Video tutorial","text":"

Info

Azure sessions are not available anymore for direct creation. Instead you can create a new Azure Integration.

"},{"location":"configuring-session/configure-aws-iam-role-chained/","title":"Configure AWS IAM Role Chained","text":""},{"location":"configuring-session/configure-aws-iam-role-chained/#what-is-an-aws-iam-role-chained-session","title":"What is an AWS IAM Role Chained session","text":"

An AWS IAM Role Chained session represents an AWS role chaining access. Role chaining is the process of assuming a role starting from another IAM role or user.

An IAM role has some similarities to an IAM user. Roles and users are both AWS identities with permissions policies that determine what the identity can and cannot do in AWS. However, instead of being uniquely associated with one person, a role is intended to be assumable by anyone who needs it.

A role does not have standard long-term credentials such as a password or access keys associated with it. Instead, when you assume a role, it provides you with temporary security credentials for your role session.

Role chaining occurs when you use a role to assume a second role through the AWS CLI or API, even in other accounts.

Info

Refer to this guide to delegate access across AWS accounts using IAM Roles chaining.

"},{"location":"configuring-session/configure-aws-iam-role-chained/#how-to-configure-an-aws-iam-role-chained-in-leapp","title":"How to configure an AWS IAM Role Chained in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Chained as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-chained/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role. ROLE SESSION NAME Your session name. You can query and search this on AWS Cloudtrail or any other linked audit service to find out what action were performed by the linked Identity. ASSUMER SESSION Your session from which this Role will be assumed. The assume-role call will be automatically made by Leapp."},{"location":"configuring-session/configure-aws-iam-role-chained/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/","title":"Configure AWS IAM Role Federated","text":""},{"location":"configuring-session/configure-aws-iam-role-federated/#what-is-an-aws-iam-role-federated-session","title":"What is an AWS IAM Role Federated session","text":"

An AWS IAM Role Federated session represents an access type that relies on a federation between an AWS account and an external Identity Provider.

AWS Identity and Access Management (IAM) supports identity federation for delegated access to the AWS Management Console or AWS APIs. With identity federation, external identities are granted secure access to resources in your AWS accounts through IAM roles.

These external identities can come from your corporate identity provider (such as Microsoft Active Directory or from the AWS Directory Service) or from a web identity provider (such as Amazon Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible provider).

We currently only support SAML 2.0 federation.

Info

  • Refer to this guide to provision your own federated roles.
  • Refer to this guide to configure and trust your SAML 2.0 Identity Provider.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#supported-saml-identity-providers","title":"Supported SAML Identity Providers","text":"Identity Provider AWS Azure GSUITE OKTA ONELOGIN AZURE AD AUTH0 KEYCLOAK JUMPCLOUD

Info

Is your SAML 2.0 Identity Provider not included in the above list? Please, refer to the FAQ to add a new one.

"},{"location":"configuring-session/configure-aws-iam-role-federated/#how-to-configure-an-aws-iam-role-federated-in-leapp","title":"How to configure an AWS IAM Role Federated in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM Role Federated as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-role-federated/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. SAML 2.0 URL Your SAML URL interface to start the authentication flow and log into your Identity provider. AWS IDENTIY PROVIDER ARN Your Identity Provider ID in AWS. You can find it in IAM section Identity Providers. ROLE ARN Your IAM Role unique ID. The active Session will refer to this Role."},{"location":"configuring-session/configure-aws-iam-role-federated/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-aws-iam-user/","title":"Configure AWS IAM User","text":""},{"location":"configuring-session/configure-aws-iam-user/#what-is-an-aws-iam-user-session","title":"What is an AWS IAM User session","text":"

An AWS Identity and Access Management (IAM) user is an entity that you create in AWS to represent the person or application that uses it to interact with AWS.

An IAM User in AWS consists of a name and a set of long-term credentials. Leapp never sets these values in the configuration files, and automatically generates and refreshes a set of short-term credentials.

Info

If you want to know how Leapp generates and refresh short-term credentials refer to the credentials generation section in the documentation.

"},{"location":"configuring-session/configure-aws-iam-user/#how-to-configure-an-aws-iam-user-in-leapp","title":"How to configure an AWS IAM User in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select Amazon AWS as the Cloud Provider.
  3. Select AWS IAM User as the access method.
  4. Provide the required information (described in the next section).
  5. Click on the Create Session button.
"},{"location":"configuring-session/configure-aws-iam-user/#required-information","title":"Required information","text":"Field Description SESSION ALIAS Your friendly session name in Leapp. Give it a meaningful name so it will be easier to find inside Leapp. NAMED PROFILE Your friendly session name in the AWS credential file. You will be able to reference it from the AWS CLI with --name. REGION Your default region of choice. Select the one which you use the most for this Session. MFA DEVICE Your MFA device ID to set up multi-factor authentication. ACCESS KEY ID Your long-term Access Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. SECRET ACCESS KEY Your long-term Secret Key. It will be used to generate a short-term set of credentials. Don't disclose it to anyone. Add AWS IAM User Screen"},{"location":"configuring-session/configure-aws-iam-user/#video-tutorial","title":"Video tutorial","text":""},{"location":"configuring-session/configure-localstack/","title":"Configure LocalStack","text":""},{"location":"configuring-session/configure-localstack/#what-is-a-localstack-session","title":"What is a LocalStack session","text":"

With LocalStack you can emulate AWS cloud services with a fully functional cloud stack on your local machine. Develop and test your cloud applications with the full cloud experience, but without the hassle of the remote cloud.

You can use Leapp to create a LocalStack session that can then be used to set your local credential file and access your LocalStack resources.

Info

You need to install LocalStack in order to use the AWS cloud emulation features

"},{"location":"configuring-session/configure-localstack/#how-to-configure-a-localstack-session-in-leapp","title":"How to configure a LocalStack session in Leapp","text":"
  1. From the top bar, click on the plus icon to add a new session.
  2. Select LocalStack as the Cloud Provider.
  3. Provide a name for the session.
  4. Click on the Create Session button.

Warning

LocalStack sessions work only with AWS Credential Method configured with the credential-file-method option. The option is available in the Options menu > General > Generics > AWS Credential Method.

Warning

In order to use the credential file to access LocalStack from your AWS CLI, you must update the AWS CLI to the latest version.

"},{"location":"contributing/get-involved/","title":"Get involved","text":""},{"location":"contributing/get-involved/#get-involved","title":"Get involved","text":"

Contributions and questions are not just welcome, they\u2019re essential! Please open issues with ideas on how to improve Leapp, including feedback, critiques, and information about how you\u2019re using it. Discussion is at the heart of the project and your thoughts and ideas will help make it better for everyone, thank you.

Read our contribution guide to learn more.

You can chat with us in our community, so join us, or feel free to contact us via the website!

Join our Community

"},{"location":"installation/install-leapp/","title":"Install Leapp","text":""},{"location":"installation/install-leapp/#install-leapp-app","title":"Install Leapp App","text":""},{"location":"installation/install-leapp/#macos-windows-and-linux","title":"MacOS, Windows, and Linux","text":"

You can install Leapp by downloading the pre-built binaries for your OS on the website release page:

Download Leapp \u21e9

Unzip the package and double-click the executable to install.

"},{"location":"installation/install-leapp/#macos-homebrew","title":"macOS (Homebrew)","text":"

Leapp can also be installed on macOS via Homebrew Cask with:

brew install leapp\n

Info

In addition, Leapp can also be installed with Linuxbrew on Windows via WSL

"},{"location":"installation/install-leapp/#install-leapp-cli","title":"Install Leapp CLI","text":"

You can install Leapp CLI through a Homebrew Formula:

brew install Noovolari/brew/leapp-cli\n

In Linux it may happen that the command leapp is not recognized. In that case we suggest to run the following command:

brew link leapp-cli\n
"},{"location":"installation/install-leapp/#install-leapp-cli-on-macos-with-arm64-chip-m1-m2","title":"Install Leapp CLI on macOS with ARM64 chip (M1, M2)","text":"

On macOS with ARM64 chip you can use the Homebrew Formula:

brew install Noovolari/brew/leapp-cli-darwin-arm64\n

All the available commands are listed in the Leapp CLI section of the documentation.

Warning

Leapp CLI will work only if the Desktop App is installed and running.

"},{"location":"installation/requirements/","title":"Requirements","text":""},{"location":"installation/requirements/#requirements","title":"Requirements","text":""},{"location":"installation/requirements/#macos-and-windows","title":"MacOS and Windows","text":"

There are no requirements for macOS and Windows users.

"},{"location":"installation/requirements/#linux-systems","title":"Linux systems","text":"

Leapp uses libsecret and gnome-keyring as dependencies to store all sensitive data into the keyring. Depending on your distribution, you may need to install them using these commands before running Leapp.

Arch LinuxDebian/UbuntuRed Hat-based
sudo pacman -S gnome-keyring\nsudo pacman -S libsecret\n
sudo apt-get install gnome-keyring\nsudo apt-get install libsecret-1-dev\n
sudo yum install gnome-keyring\nsudo yum install libsecret-devel\n
"},{"location":"installation/requirements/#logging-into-ec2-instances-via-aws-ssm-with-leapp","title":"Logging into EC2 Instances via AWS SSM with Leapp","text":"

In order to use AWS SSM on your System through Leapp, you must be able to execute this command on your own at least once, when the correct credentials are active.

aws ssm start-session --region <region> --target <instanceId>\n

If, for any reason, this command fails, please verify that you have Python 3.x installed:

https://www.python.org/downloads/\n

Also verify that the AWS SSM Agent is installed correctly by following the official AWS guide:

https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-v3.html\n
"},{"location":"installation/update-leapp/","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#update-leapp","title":"Update Leapp","text":""},{"location":"installation/update-leapp/#desktop-app","title":"Desktop App","text":"

Leapp checks if a new version is available every 10 minutes (starting from the application launch). If so, a dialog message will pop up and show a version number, the release date and the changelog

In this modal, a user can do the following:

Remind me laterDownload updateClick on X

Leapp will close the modal and notify the user that a new update is available by adding a notification dot to the Dock Bar icon. Users will not be bothered anymore until the next release is available. This option is convenient for users that want to stick to a specific version. Note that you can do this for every version and maintain the one you prefer.

Leapp will open the Release URL in your default browser to let the User manually download the release for their specific OS and install it.

Leapp will close the modal and another one will appear in 10 minutes.

"},{"location":"installation/update-leapp/#macos-homebrew-linux-linuxbrew-and-windows-via-wsl","title":"macOS (Homebrew), Linux (Linuxbrew) and Windows (via WSL)","text":"

Leapp can also be updated via Homebrew Cask with: brew upgrade leapp

"},{"location":"installation/update-leapp/#cli","title":"CLI","text":"

Depending on which method you used to install the CLI (npm or Homebrew on macOS), you can update it with the following commands:

npmHomebrew (macOS)
npm update -g @noovolari/leapp-cli\n
brew upgrade Noovolari/brew/leapp-cli\n
"},{"location":"leapp-pro/export-pro-workspace/","title":"Export PRO Workspace","text":""},{"location":"leapp-pro/export-pro-workspace/#how-to-export-your-pro-workspace","title":"How to export your Pro Workspace","text":"
  1. create a backup of your ~/.Leapp/Leapp-lock.json file;
    // From ~/.Leapp directory run the following command:\ncp Leapp-lock.json Leapp-lock.json.bkp\n
  2. log into you Pro Workspace using the Desktop App;

  3. from the Leapp Options \"General\" tab, click the button next to the \"Export Pro/Team workspace\" label;

  4. close the Leapp Options dialog;

  5. close Leapp (on macOS \u2318+Q);
  6. you should see a Leapp-lock.json.exported file in the ~/.Leapp folder;
  7. remove the Leapp-lock.json file and rename Leapp-lock.json.exported to Leapp-lock.json;
    rm Leapp-lock.json\nmv Leapp-lock.json.exported Leapp-lock.json\n
  8. re-open Leapp;
  9. switch to the Local Workspace;
  10. you should now see your Pro Workspace migrated into the Local one.
"},{"location":"plugins/plugins-development/","title":"Developer Reference","text":"

This document is a Plugin SDK reference. The Plugin SDK is part of Leapp Core and contains Base Classes that describe different types of plugins.

"},{"location":"plugins/plugins-development/#pluginenvironment","title":"PluginEnvironment","text":"

A wrapper class used to expose a minumum set of methods from Leapp Core.

Currently available methods:

"},{"location":"plugins/plugins-development/#log","title":"log","text":"
  • log(message: string, level: PluginLogLevel, display: boolean): void

Log a custom message in Leapp or in the log file

argument type description message string the message to show level LogLevel severity of the message display boolean shows the message in a toast in the desktop app when true. Otherwise, log it in the log files"},{"location":"plugins/plugins-development/#fetch","title":"fetch","text":"
  • fetch(url: string): any

Retrieve the content of a URL. Returns a promise for the URL

argument type description url string a valid HTTP URL to fetch from"},{"location":"plugins/plugins-development/#openexternalurl","title":"openExternalUrl","text":"
  • openExternalUrl(url: string): void

Open an external URL in the default browser

argument type description url string a valid HTTP URL to open in the default browser"},{"location":"plugins/plugins-development/#createsession","title":"createSession","text":"
  • createSession(createSessionData: SessionData): Promise<string>

Creates a new Leapp Session based on given SessionData

argument type description createSessionData SessionData the metadata used to create the Leapp Session"},{"location":"plugins/plugins-development/#clonesession","title":"cloneSession","text":"
  • cloneSession(session: Session): Promise<string>

This method allows you to clone the given Leapp Session. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description session Session the Leapp Session that I want to clone"},{"location":"plugins/plugins-development/#updatesession","title":"updateSession","text":"
  • updateSession(updateSessionData: SessionData, session: Session): Promise<void>

This method allows you to update the given session with the given updateSessionData. This operation is allowed for the following Leapp Session types:

  • AwsIamUserSession
  • AwsIamRoleFederatedSession
  • AwsIamRoleChainedSession
argument type description updateSessionData SessionData the metadata used to update the given Leapp Session session Session the Leapp Session that I want to update"},{"location":"plugins/plugins-development/#openterminal","title":"openTerminal","text":"
  • openTerminal(command: string, env?: any): Promise<void>

Execute the given command in the platform-specific terminal; optionally, it is possible to set an env key/value object containing the env variables to export in the terminal, before the command execution.

The terminal window base path is set to the home directory.

argument type description command string the command that I want to execute in the platform-specific terminal env any optional key/value env variables object"},{"location":"plugins/plugins-development/#getprofileidbyname","title":"getProfileIdByName","text":"
  • getProfileIdByName(profileName: string): string

Returns the id of a named profile from its name if it exists, otherwise creates a new profile and returns its id.

Can be used when creating/editing a session since SessionData requires the id of a named profile

argument type description profileName string a valid named profile"},{"location":"plugins/plugins-development/#getidpurlidbyurl","title":"getIdpUrlIdByUrl","text":"
  • getIdpUrlIdByUrl(url: string): string

Return the ID of the IdpUrl object from the given URL if it exists, otherwise creates a new IdP URL and returns its ID.

Can be used when creating/editing Federated Sessions since SessionData requires the ID of an IdP URL.

argument type description url string the URL associated with the IdpUrl I want to retrieve"},{"location":"plugins/plugins-development/#example-display-a-toast-message-in-leapp","title":"Example: display a toast message in Leapp","text":"
this.pluginEnvironment.log(\"Hello World\", LogLevel.info, true);\n
"},{"location":"plugins/plugins-development/#example-fetch-basic-usage","title":"Example: fetch basic usage","text":"
const res = await this.pluginEnvironment.fetch(\"\"); //Insert a custom URL\nconst response = await res.json();\n
"},{"location":"plugins/plugins-development/#example-open-a-url-in-the-browser","title":"Example: open a URL in the browser","text":"
this.pluginEnvironment.openExternalUrl(\"https://leapp.cloud\");\n
"},{"location":"plugins/plugins-development/#example-create-a-session","title":"Example: create a session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n\n    this.pluginEnvironment.createSession(new AwsIamRoleFederatedSessionData(\n      \"arn:aws:iam::000000000000:saml-provider/test\",\n      idpUrlId,\n      profileId,\n      \"us-east-1\",\n      \"arn:aws:iam::000000000000:role/test\",\n      \"New Name Session\"\n    ));\n}\n
"},{"location":"plugins/plugins-development/#example-edit-the-selected-session","title":"Example: edit the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    const profileId = this.pluginEnvironment.getProfileIdByName(\"default\");\n    const idpUrlId = this.pluginEnvironment.getIdpUrlIdByUrl(\"put a valid url for an IdP here\");\n    this\n    .pluginEnvironment.updateSession(new AwsIamRoleFederatedSessionData(\n        \"arn:aws:iam::000000000000:saml-provider/test\", \n        idpUrlId, \n        profileId, \n        \"us-east-1\", \n        \"arn:aws:iam::000000000000:role/test\", \n        \"New Name Session\"\n    ), session);\n}\n
"},{"location":"plugins/plugins-development/#example-clone-the-selected-session","title":"Example: clone the selected session","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    await this.pluginEnvironment.cloneSession(session);\n}\n
"},{"location":"plugins/plugins-development/#awscredentialsplugin","title":"AwsCredentialsPlugin","text":"

A base class that needs to be extended by a plugin and serves as the action class.

After extending this class, you need to implement these methods:

"},{"location":"plugins/plugins-development/#applysessionaction","title":"applySessionAction","text":"
  • applySessionAction(session: Session, credentials: any): Promise<void>

Run your custom action

argument type description session Session the Leapp session you run the action from credentials any Leapp temporary-generated credentials

The credentials object has the following structure:

export interface CredentialsInfo {\n  sessionToken: {\n    aws_access_key_id: string;\n    aws_secret_access_key: string;\n    aws_session_token: string;\n    region: string;\n  }\n}\n
"},{"location":"plugins/plugins-development/#get-actioname","title":"get actioName","text":"
  • get actionName(): string>

Return a name for the action that will be display in Leapp (e.g. \"My Awesome Plugin\")

"},{"location":"plugins/plugins-development/#get-actionicon","title":"get actionIcon","text":"
  • get actionIcon(): string

Return a valid FontAwesome 5 code. Override default value in package.json

"},{"location":"plugins/plugins-development/#example-display-a-session-based-message-in-leapp","title":"Example: display a session-based message in Leapp","text":"
async applySessionAction(session: Session, credentials: any): Promise<void> {\n    if(session.type === Session.awsIamUser) {\n        this.pluginEnvironment.log(`This is an IAM User session: ${session.sessionName}`, LogLevel.info, true); \n    }\n    else {\n        this.pluginEnvironment.log(`This is NOT an IAM User session: ${session.sessionName}`, LogLevel.info, true);\n    }\n}\n
"},{"location":"plugins/plugins-development/#packagejson-metadata","title":"package.json metadata","text":"property values description constraints name a custom string the name of the plugin the same used in the plugin folder author a custom string the name of the author none version a custom string the version of the plugin must be a semver string description a custom string the description of the plugin none keywords a string array the name of the plugin must contain at least \"leapp-plugin\" leappPlugin an object the plugin custom configuration must contain at least \"supportedOS\" and \"supportedSessions\" leappPlugin.supportedOS a string array [\"mac\", \"windows\", \"linux\"] if not specified, all OSs will be considered compatible leappPlugin.supportedSessions a string array [\"anyType, \"aws\", \"azure\", \"awsIamRoleFederated\", \"awsIamRoleChained\", \"awsSsoRole\", \"awsIamUser\"] at least one of these values must be specified leappPlugin.icon a custom string fontAwesome code for an icon (e.g. \"fa fa-globe\") must be a valid FontAwesome 5 code"},{"location":"plugins/plugins-development/#plugin-examples","title":"Plugin Examples","text":""},{"location":"plugins/plugins-development/#open-web-console","title":"Open Web Console","text":"
import { Session } from \"@noovolari/leapp-core/models/session\";\nimport { AwsCredentialsPlugin } from \"@noovolari/leapp-core/plugin-sdk/aws-credentials-plugin\";\nimport { PluginLogLevel } from \"@noovolari/leapp-core/plugin-sdk/plugin-log-level\";\n\nexport class WebConsolePlugin extends AwsCredentialsPlugin {\n  get actionName(): string {\n    return \"Open web console\";\n  }\n\n  get actionIcon(): string {\n    return \"fa fa-globe\";\n  }\n\n  async applySessionAction(session: Session, credentials: any): Promise<void> {\n    this.pluginEnvironment.log(\"Opening web console for session: \" + session.sessionName, PluginLogLevel.info, true);\n\n    const sessionRegion = session.region;\n    const sessionDuration = 3200;\n    const isUSGovCloud = sessionRegion.startsWith(\"us-gov-\");\n    let federationUrl;\n    let consoleHomeURL;\n\n    if (!isUSGovCloud) {\n      federationUrl = \"https://signin.aws.amazon.com/federation\";\n      consoleHomeURL = `https://${sessionRegion}.console.aws.amazon.com/console/home?region=${sessionRegion}`;\n    } else {\n      federationUrl = \"https://signin.amazonaws-us-gov.com/federation\";\n      consoleHomeURL = `https://console.amazonaws-us-gov.com/console/home?region=${sessionRegion}`;\n    }\n\n    if (sessionRegion.startsWith(\"cn-\")) {\n      throw new Error(\"Unsupported Region\");\n    }\n\n    this.pluginEnvironment.log(\"Starting opening Web Console\", PluginLogLevel.info, true);\n\n    const sessionStringJSON = {\n      sessionId: credentials.sessionToken.aws_access_key_id,\n      sessionKey: credentials.sessionToken.aws_secret_access_key,\n      sessionToken: credentials.sessionToken.aws_session_token,\n    };\n\n    const queryParametersSigninToken = `?Action=getSigninToken&SessionDuration=${sessionDuration}&Session=${encodeURIComponent(\n      JSON.stringify(sessionStringJSON)\n    )}`;\n\n    const res = await this.pluginEnvironment.fetch(`${federationUrl}${queryParametersSigninToken}`);\n    const response = await res.json();\n\n    const loginURL = `${federationUrl}?Action=login&Issuer=Leapp&Destination=${consoleHomeURL}&SigninToken=${(response as any).SigninToken}`;\n    this.pluginEnvironment.openExternalUrl(loginURL);\n  }\n}\n
"},{"location":"plugins/plugins-introduction/","title":"Introduction to Plugins","text":"

This section provides an overview of Leapp\u2019s plugins, which can be used to extend the functionality of Leapp.

Plugins are commonly used when more advanced and custom behavior is needed, for example using Leapp-generated temporary credentials to run custom actions.

You can create your own plugins or import custom ones created by the community. You can also publish your plugins on npm to make them available to everyone easily.

"},{"location":"plugins/plugins-introduction/#add-a-plugin","title":"Add a Plugin","text":"

To add a plugin you can use one of the following methods:

"},{"location":"plugins/plugins-introduction/#add-from-npm","title":"Add from npm","text":"

From the Leapp option menu, go to the Plugins tab. Insert the name of the npm package for the plugin and click on the plus icon to add it to your plugins

"},{"location":"plugins/plugins-introduction/#add-manually","title":"Add manually","text":"

Go to Options by clicking the top right gear icon then click the Plugins tab. Click the Folder Icon. This will open the plugin folder inside .Leapp.

Here, manually create a folder with the same name as your plugin package.json name property and move your package.json and bundled plugin.js files inside this folder.

Alternatively, you can simply move your entire plugin folder cloned from the example template.

Lastly, from the Leapp Plugins tab in the Option menu, click on the refresh icon to reload all plugins.

Warning

Adding plugins is at your own risk! We cannot currently guarantee that a plugin is safe, so BE CAREFUL when you install something from an unknown source. A plugin verification system is under development and will be available later this year.

"},{"location":"plugins/plugins-introduction/#disable-a-plugin","title":"Disable a Plugin","text":"

To disable a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Toggle Enabled for the plugin you want to disable.

"},{"location":"plugins/plugins-introduction/#remove-a-plugin","title":"Remove a Plugin","text":"

To remove a Leapp plugin, go to Options by clicking the top right gear icon then click the Plugins tab.

Click the Folder Icon. This will open the plugin folder inside .Leapp. From here, locate the folder containing the plugin you want to remove and simply delete the folder.

"},{"location":"plugins/plugins-introduction/#run-a-plugin","title":"Run a Plugin","text":"

You can run a plugin both from Leapp Desktop App and Leapp CLI.

From Leapp Desktop App, right click on a session to open the contextual menu, click on Plugins, and select the plugin you want to run

Info

This contextual menu option is not available if you have no plugins that you can run on the selected session and/or your operating system.

From Leapp CLI, you can use the command leapp session run-plugin. For more information on how to use this CLI command, see the documentation.

"},{"location":"plugins/plugins-introduction/#plugin-menu","title":"Plugin Menu","text":"

Click on the top right gear icon to go to the Leapp option menu and then select the tab Plugin.

From there, you can see a list of currently installed plugins, check whether a plugin is compatible with your system or not, which session types it supports and disable/enable it if you need.

"},{"location":"plugins/plugins-introduction/#create-your-plugin","title":"Create your Plugin","text":"

You can start creating a plugin from the template.

Leapp plugins are written in TypeScript. They must contain at least a class that extends a base class provided by the Plugin SDK.

There's currently only one of these classes, AwsCredentialsPlugin , that can be used to create a plugin that generates temporary credentials.

Every Leapp plugin must at least have a package.json file and a plugin.js file.

leapp-plugin/             \n \u251c\u2500\u2500 package.json      # Plugin metadata\n \u2514\u2500\u2500 plugin.js         # A webpack bundle for the main logic\n

Create your Plugin

"},{"location":"security/credential-process/","title":"Credential Process","text":""},{"location":"security/credential-process/#what-is-credential-process","title":"What is Credential Process?","text":"

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the \"credential file\" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

"},{"location":"security/credential-process/#how-credential-process-works","title":"How Credential Process works?","text":"

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{\n  \"Version\": 1,\n  \"AccessKeyId\": \"an AWS access key\",\n  \"SecretAccessKey\": \"your AWS secret access key\",\n  \"SessionToken\": \"the AWS session token for temporary credentials\", \n  \"Expiration\": \"ISO8601 timestamp when the credentials expire\"\n}  \n

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

"},{"location":"security/credential-process/#advantages","title":"Advantages","text":"
  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

"},{"location":"security/credential-process/#how-leapp-works-with-credential-process","title":"How Leapp works with Credential Process","text":"

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel ().

2) In the general section change the AWS Credential Generation from \"credential-file-method\" to \"credential-process-method\".

3) An informative panel will show up telling that you need the CLI installed (see below), click on \"I acknowledge it\"

warning modal

4) Now, everytime you click on start () an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]\ncredential_process=leapp session generate SESSION_ID\nregion=REGION\n

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

"},{"location":"security/intro/","title":"Intro","text":"

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc. Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc."},{"location":"security/intro/#end-to-end-encryption","title":"End-to-end Encryption","text":"

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

"},{"location":"security/system-vault/","title":"System Vault","text":"

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

"},{"location":"security/system-vault/#supported-system-vaults","title":"Supported System Vaults","text":"OS System Vault MacOS Keychain Windows Credential Vault Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

"},{"location":"security/zero-knowledge/","title":"Zero Knowledge","text":"

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

"},{"location":"security/zero-knowledge/#users-have-key-control","title":"Users have key control","text":"

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

"},{"location":"security/zero-knowledge/#criteria","title":"Criteria","text":"
  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.
"},{"location":"security/zero-knowledge/#technologies","title":"Technologies","text":"
  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
"},{"location":"security/credentials-generation/aws/","title":"Credential file","text":"

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

"},{"location":"security/credentials-generation/aws/#iam-federated-role","title":"IAM Federated Role","text":""},{"location":"security/credentials-generation/aws/#assumerolewithsaml","title":"assumeRoleWithSAML","text":"

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

\u26a0\ufe0f In this case, generated credentials are not \"cached\" in the keychain.

"},{"location":"security/credentials-generation/aws/#iam-chained-role","title":"IAM Chained Role","text":"

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

"},{"location":"security/credentials-generation/aws/#iam-user","title":"IAM User","text":"

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

"},{"location":"security/credentials-generation/aws/#aws-sso-role","title":"AWS SSO Role","text":"

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

"},{"location":"security/credentials-generation/azure/","title":"Azure","text":""},{"location":"security/credentials-generation/azure/#azure-credentials-generation","title":"Azure credentials generation","text":"

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API. Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

"},{"location":"security/credentials-generation/azure/#access-strategy-login-integration","title":"Access strategy - login integration","text":"

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.
"},{"location":"security/credentials-generation/azure/#access-strategy-start-session","title":"Access strategy - start session","text":"

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source
"},{"location":"security/credentials-generation/azure/#access-strategy-rotate-session","title":"Access strategy - rotate session","text":"

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.
"},{"location":"security/credentials-generation/azure/#access-strategy-stop-session","title":"Access strategy - stop session","text":"

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

"},{"location":"troubleshooting/app-data/","title":"Application Data","text":""},{"location":"troubleshooting/app-data/#default-leapp-directories","title":"Default Leapp directories","text":"

Here the user can find all the directories that Leapp uses directly or indirectly.

"},{"location":"troubleshooting/app-data/#installation-path","title":"Installation path","text":"

By default, Leapp is installed in the following locations:

MacOSLinuxWindows
/Applications\n
/opt/Leapp\n
C:\\Users\\<USER>\\AppData\\Local\\Programs\\Leapp\n
"},{"location":"troubleshooting/app-data/#configuration-files","title":"Configuration files","text":"

By default, Leapp stores the configuration files in the following locations:

MacOSLinuxWindows
~/.Leapp\n
~/.Leapp\n
C:\\Users\\<USER>\\.Leapp\n

Info

  • Leapp-lock.json stores the Leapp configuration and is encrypted.
    • On startup, if Leapp-lock.json is not found, Leapp will create an empty version of it.
  • Leapp-lock.backup.bin stores a backup of Leapp-lock.json and is updated on startup if Leapp-lock.json is considered valid.
    • On startup, if Leapp-lock.json is corrupted, Leapp-lock.backup.bin will be used to restore it.
    • If both files are corrupted, a new empty configuration will be created.
  • .latest contains the latest version number of Leapp. If missing, it will be created again on startup.
"},{"location":"troubleshooting/app-data/#credentials-file","title":"Credentials file","text":"

By default, Leapp writes the credentials file in the following locations:

MacOSLinuxWindows
~/.aws\n
~/.aws\n
C:\\Users\\<USER>\\.aws\n
"},{"location":"troubleshooting/app-data/#logs-file","title":"Logs file","text":"

By default, Leapp writes logs to the following locations:

MacOSLinuxWindows
~/Library/Logs/Leapp/log.electronService.log\n
~/.config/Leapp/logs/log.electronService.log\n
C:\\Users\\<USER>\\AppData\\Roaming\\Leapp\\log.electronService.log\n

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}\n

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

"},{"location":"troubleshooting/faq/","title":"FAQ","text":""},{"location":"troubleshooting/faq/#im-using-the-open-source-app-do-you-store-my-data-online","title":"I'm using the open-source app, do you store my data online?","text":"

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

"},{"location":"troubleshooting/faq/#ive-got-a-paid-tier-how-do-you-manage-my-data-can-you-access-it","title":"I've got a paid tier, how do you manage my data? Can you access it?","text":"

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

"},{"location":"troubleshooting/faq/#i-dont-feel-secure-using-a-built-in-window-for-authentication-cant-you-use-the-default-browser","title":"I don't feel secure using a built-in window for authentication, can't you use the default browser?","text":"

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

"},{"location":"troubleshooting/faq/#how-can-i-find-leapp-data-in-the-system-vault","title":"How can I find Leapp data in the System Vault?","text":"

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

"},{"location":"troubleshooting/faq/#where-do-i-find-the-leapp-logs","title":"Where do I find the Leapp logs?","text":"

Head to the Application data section.

"},{"location":"troubleshooting/faq/#ssm-terminal-is-opening-but-no-session-is-starting-what-can-i-do","title":"SSM terminal is opening but no session is starting, what can I do?","text":"

Just close the terminal and relaunch the SSM command.

"},{"location":"troubleshooting/faq/#aws-cli-or-az-cli-is-installed-but-leapp-cant-find-it-what-can-i-do","title":"AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?","text":"

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws\nln -s /path/to/my/az /usr/local/bin/az\n
"},{"location":"troubleshooting/faq/#i-use-leapp-session-current-but-want-to-see-the-alias-and-not-the-id","title":"I use leapp session current but want to see the alias and not the id.","text":""},{"location":"troubleshooting/faq/#setting-up-leappalias-command","title":"Setting up leappalias command","text":"

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash\nleapp session current | grep -o \"\\\"alias\\\":\\\"[^\\\"]*\" | cut -d '\"' -f 4\n
  • Save the file and make it executable by running the following command in the terminal:
chmod +x leappalias.sh\n
  • Move the script to a directory in your system's PATH. For example, /usr/local/bin/:
sudo mv leappalias.sh /usr/local/bin/leappalias\n
  • Open your zshrc file using a text editor:
nano ~/.zshrc\n
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'\n
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc\n

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

"},{"location":"troubleshooting/faq/#how-can-i-add-support-to-a-new-saml-20-identity-provider","title":"How can I add support to a new SAML 2.0 Identity Provider?","text":"

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

"},{"location":"usefull-scripts/export-profile/","title":"Useful Scripts","text":""},{"location":"usefull-scripts/export-profile/#aws-profile-selector-simplifying-aws-profile-selection-with-the-leapp-cli","title":"AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI","text":"

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {\n    local selected_profile\n    selected_profile=$(leapp session list | \\\n        grep -w 'active' | \\\n        awk '{print $(NF-2)}' | \\\n        fzf --height 30% -1 -0 --header 'Select AWS profile')\n    if [[ -n \"$selected_profile\" ]]; then\n        export AWS_PROFILE=\"$selected_profile\"\n        echo \"AWS_PROFILE=$AWS_PROFILE\"\n    fi\n}\n\nalias awsp=select_and_export_aws_profile\n

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

"}]} \ No newline at end of file diff --git a/latest/security/credential-process/index.html b/latest/security/credential-process/index.html index ccfa8761d..6efd8417b 100644 --- a/latest/security/credential-process/index.html +++ b/latest/security/credential-process/index.html @@ -1,4 +1,4 @@ - Credential Process - Leapp - Docs

Credential Process

What is Credential Process?

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the "credential file" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

How Credential Process works?

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{
+ Credential Process - Leapp - Docs      

Credential Process

What is Credential Process?

Credential Process is a configuration option (in the AWS config file) that instruct the AWS CLI and SDKs to use an external command to generate valid credentials in a specific format.

It is a way to generate AWS compatible credentials on the fly, only when requested by tools that respect the AWS credential chain.

Credential Process is perfect if you have a way to generate or look up credentials that isn't directly supported by the AWS CLI or third-party tools; for example, you can configure the AWS CLI to use it by configuring the credential_process setting in the config file.

The difference between Credential Process and Standard Credential file is that credentials in the "credential file" are written in plain text and so, they are potentially unsecure, even if temporary. Credential Process instead, generates credentials that are consumed only when they are effectively needed.

No credential is written in any file. They are printed on the stdout and consumed upon request.

How Credential Process works?

Credential Process asks an external process to generate an AWS compatible temporary credential set in this format:

{
   "Version": 1,
   "AccessKeyId": "an AWS access key",
   "SecretAccessKey": "your AWS secret access key",
@@ -8,4 +8,4 @@
 

The Expiration field allows the generated credentials to be cached and reused until they are no more valid (by default the value is 3600s=1h).

Advantages

  • Ensures that no credential set is written on your machine in neither the ~/.aws/credentials or ~/.aws/config files.
  • Ensures your long-running tasks always have valid credentials during their lifecycle.
  • Is compatible with named-profiles.
  • Is a way to make third-party tool compatible with AWS SSO and SAML Federated IAM Principals even if they don't support them natively.
  • As stated by this article by Ben Kehoe, Credential Process is a good way to avoid cluttering the credential file with temporary credentials.

Warning

Temporary credentials in the credentials file reduce potential blast radius in case of machine exploit but they require to be refreshed every time they expire.

How Leapp works with Credential Process

Info

Requirements: this credentials generation method requires that both Leapp desktop app and CLI are installed.

1) Open your Leapp desktop app and go to the settings panel (option icon).

2) In the general section change the AWS Credential Generation from "credential-file-method" to "credential-process-method".

3) An informative panel will show up telling that you need the CLI installed (see below), click on "I acknowledge it"

warning modal
warning modal

4) Now, everytime you click on start (start session icon) an entry will be created in the ~/.aws/config file with the following format:

[profile PROFILE_NAME]
 credential_process=leapp session generate SESSION_ID
 region=REGION
-

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

\ No newline at end of file +

5) You can start more than one session, depending on how many named-profile you've created; for every session started with a unique named-profile, a new entry will be created in the config file.

Info

AWS CLI, SDks, and third-party tools that can read credentials from the config file can reach AWS services with this method.

\ No newline at end of file diff --git a/latest/security/credentials-generation/aws/index.html b/latest/security/credentials-generation/aws/index.html index 3734ca94a..4e32928fb 100644 --- a/latest/security/credentials-generation/aws/index.html +++ b/latest/security/credentials-generation/aws/index.html @@ -1 +1 @@ - Credential file - Leapp - Docs

Credential file

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

IAM Federated Role

assumeRoleWithSAML

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

⚠️ In this case, generated credentials are not "cached" in the keychain.

IAM Chained Role

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

IAM User

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

AWS SSO Role

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

\ No newline at end of file + Credential file - Leapp - Docs

Credential file

Leapp manages 4 types of AWS access methods:

  1. IAM Federated Role
  2. IAM User
  3. IAM Single Sign-On
  4. IAM Role chained

For each access method, Leapp generates a set of temporary credentials through STS and a rotation logic is triggered every 20 minutes.

Temporary credentials ensures that no long-term credentials are written in the AWS credentials file located in ~/.aws/credentials.

Leapp manages information entered by the user using the following logic for each access method.

IAM Federated Role

assumeRoleWithSAML

Temporary security credentials created by AssumeRoleWithSAMLResponse last for one hour. However, you can use the optional DurationSeconds parameter to specify the duration of your session.

Your role session lasts for the specified duration, or until the time specified in the SAML authentication response's SessionNotOnOrAfter value, whichever is shorter. You can provide a DurationSeconds value from 900 seconds (15 minutes) up to the maximum session duration setting for the role. This setting can have a value from 1 hour to 12 hours.

Leapp sets the token duration to 1 hour.

Info

⚠️ In this case, generated credentials are not "cached" in the keychain.

IAM Chained Role

An IAM Chained Role is used to access another AWS account services through a main session with a trust relationship.

How to use AWS Javascript SDK to Assume a Role

How to generate temporary credentials on AWS

If you do not pass the DurationSeconds parameter (as in the case of Leapp), the temporary credentials expire in 1 hour.

IAM User

The GetSessionToken operation must be called by using the long-term AWS security credentials of the AWS IAM user. Credentials that are created by IAM users are valid for the duration that you specify. This duration can range from 900 seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours), with a default of 43,200 seconds (12 hours). Credentials based on account credentials can range from 900 seconds (15 minutes) up to 3,600 seconds (1 hour), with a default of 1 hour.

Leapp sets the token duration to 10 hours.

Info

These are the only temporary credentials that are stored in the System vault and not rotated, unless expired.

AWS SSO Role

How to generate SSO temporary credentials

Info

The access token is valid for 8 hours as noted in the expiresAt timestamp in the JSON file. Expired tokens must be re-authenticated using the get-role-credentials API call.

Token duration is fixed to 8 hours.

\ No newline at end of file diff --git a/latest/security/credentials-generation/azure/index.html b/latest/security/credentials-generation/azure/index.html index 631d1fddc..12f80ee61 100644 --- a/latest/security/credentials-generation/azure/index.html +++ b/latest/security/credentials-generation/azure/index.html @@ -1 +1 @@ - Azure - Leapp - Docs

Azure

Azure credentials generation

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API.
Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

Access strategy - login integration

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.

Access strategy - start session

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source

Access strategy - rotate session

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.

Access strategy - stop session

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

\ No newline at end of file + Azure - Leapp - Docs

Azure

Azure credentials generation

Azure generates a set of access and refresh tokens that are put inside the msal_token_cache.json file inside the .azure directory. Following is the procedure used to generate a set of credentials.

Info

In Windows OS the msal_token_cache is persisted on an encrypted file with dpapi API.
Starting from release 2.30 of Azure CLI, credentials are no more persisted in the original accessToken.json

Azure Users profile info is saved in the azureProfile.json file inside the .azure directory.

Access strategy - login integration

Before accessing Azure sessions, you now have to create an Azure integration. After that, these are the steps required to log in and then retrieve Azure sessions.

  1. msal_token_cache and azureProfile.json files are cleaned for security reasons.
  2. We execute az login --tenantId <TENANTID>. We do this to obtain the updated user profile and the refresh token (associated to this integration).
  3. We extract all the Azure subscriptions associated with the integration and for each one we map a Leapp Azure session.
  4. We extract the refresh token, account, and profile information from msal_token_cache and azureProfile.json and persist them in the System's vault.
  5. We also remove the previous information from the original files, to increase security and avoid external tampering.

Access strategy - start session

Info

In the current version of Leapp we can only start one Azure session at a time.

For each subscription retrieved upon login to a specific integration, we define a new Leapp Azure Session. To start an Azure session we follow these steps.

  1. Recover refresh token, account, and profile information from the Vault and we use them alongside sessionId (Subscription id) in the start operation.
  2. azureProfile.json is only filled with profile information from the current subscription.
  3. We write the account information and the refresh token back in the msal_token_cache
  4. We execute az account get-access-token --subscriptionId <SUBSCRIPTIONID>, to retrieve the access token and the id token of the subscription.
  5. The previous command also writes access and id token back to the msal_token_cache file.
  6. We update the expiration time of the session to the current datetime.
  7. We update the refresh token in the Vault with the new information.
  8. We remove the refresh token from the msal_token_cache.
  9. We finally start the session.

Info

  • The refresh token is a long term credential that potentially lasts for 90 days. The access token is a short term credential and lasts for 70 minutes. Source

Access strategy - rotate session

To rotate the session's credentials we do the following steps:

  1. We obtain the expiration time from the session we are rotating.
  2. We check with the current date to see if the session validity will expire in the next 20 minutes.
  3. If no, no other checks are necessary you can still use the current credentials.
  4. If yes, we do the following operations:

    • Remove access token from msal_token_cache.
    • Recover refresh token from System's Vault.
    • Insert the refresh token back into the msal_token_cache file.
    • We redo the last 4 steps (6-9) from the start operation.

Access strategy - stop session

To stop the session (because we only have one active at a time) we do the following steps:

  1. We run az logout, and we set session's status to INACTIVE. This operation cleans both msal_token_cache and azureProfile.json files.

Info

Leapp enhances security by forcingly refresh access token every 20 minutes and by removing refresh token from the msal_token_cache.

\ No newline at end of file diff --git a/latest/security/intro/index.html b/latest/security/intro/index.html index 752a6adf2..a8b524292 100644 --- a/latest/security/intro/index.html +++ b/latest/security/intro/index.html @@ -1 +1 @@ - Intro - Leapp - Docs

Intro

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples
Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc.
Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc.

End-to-end Encryption

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

\ No newline at end of file + Intro - Leapp - Docs

Intro

Leapp is built with a security-first approach. Every piece of information that has to be persisted is encrypted and saved on your workstation.

We devised two main methods to store data, based on its sensitiveness.

Data Persistence and encryption Examples
Operational All information used to make Leapp work, not strictly tied to direct access to cloud environments. Stored and encrypted in a configuration file within the user workspace. Named profiles, proxy configurations, etc.
Sensitive Information that can be used, or potentially exploited, to gain access to cloud environments. Stored in the System Vault, leveraging its own integrated encryption. Static credentials, access tokens, cached data, etc.

End-to-end Encryption

We leverage Zero-Knowledge to provide end-to-end encryption on tiers that require to save your data outside of your workstation to deliver specific features.

Zero Knowledge is designed so that no one, except you, can access your secured data.

Warning

We CAN'T access your data under any circumstances, even if you ask us to!

\ No newline at end of file diff --git a/latest/security/system-vault/index.html b/latest/security/system-vault/index.html index a426360aa..0e74366fc 100644 --- a/latest/security/system-vault/index.html +++ b/latest/security/system-vault/index.html @@ -1 +1 @@ - System Vault - Leapp - Docs

System Vault

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

Supported System Vaults

OS System Vault
MacOS Keychain
Windows Credential Vault
Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

\ No newline at end of file + System Vault - Leapp - Docs

System Vault

Information that can be used, or potentially exploited, to gain access to cloud environments are stored your workstation's System Vault, leveraging its own integrated encryption. The user can access the secrets stored in the System Vault at any time, using their user password.

Leapp uses Keytar as an interface to the secure vault on macOS, Windows and Linux systems.

Every key is stored in the vault under the name Leapp. In the description, you will find the underlying name used by Leapp to retrieve the secret.

Supported System Vaults

OS System Vault
MacOS Keychain
Windows Credential Vault
Linux API/Libsecret

Info

We're currently supporting only System Vaults installed by default on the OS. We're planning on extending support to other vaults and online password managers (LastPass, BitWarden, 1Password, etc.). If you'd like other services to be supported feel free to open an Issue or make a Pull Request (check our contributing guidelines).

\ No newline at end of file diff --git a/latest/security/zero-knowledge/index.html b/latest/security/zero-knowledge/index.html index ead74708b..8e6d38d88 100644 --- a/latest/security/zero-knowledge/index.html +++ b/latest/security/zero-knowledge/index.html @@ -1 +1 @@ - Zero Knowledge - Leapp - Docs

Zero Knowledge

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

Users have key control

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

Criteria

  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.

Technologies

  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
\ No newline at end of file + Zero Knowledge - Leapp - Docs

Zero Knowledge

To persist your configuration online, we implemented Zero-Knowledge encryption to prevent access to your information. But how can you trust a company to keep all of your secrets secret? The answer lies in end-to-end encryption, which lays the groundwork for applications with Zero-Knowledge architectures.

Zero-knowledge refers to policies and architecture that eliminate the possibility for secret managers themselves to access your password.

Warning

This is implemented to save your configuration online in the PRO and TEAM versions of Leapp. Don't know yet about the PRO and TEAM versions? Check our roadmap.

Info

This same process is leveraged by Bitwarden to store their password.

Users have key control

When users have complete control of the encryption key, they control access to the data, providing encrypted information to Leapp without Leapp having access to or knowledge of that data.

Info

To know more about this, you can find the whitepaper on which we based our implementation of Zero-Knowledge end-to-end encryption.

Criteria

  • During any phase of the registration and login process the client does not provide any password-related info to the server.
  • The server does not store any information that can be used to guess the password in a convenient way. In other words, the system must not be prone to brute force or dictionary attacks.
  • Any sensible data is encrypted client-side, the server will work with encrypted blocks only.
  • All the implementation is released as open-source.

Technologies

  • PBKDF2 for client hashing.
  • AES 256 for symmetric cypher.
  • RSA with 4096-bit keys for asymmetric cypher.
  • BCrypt for server hashing.
\ No newline at end of file diff --git a/latest/sessions/index.html b/latest/sessions/index.html index b09c8951a..46dc4e054 100644 --- a/latest/sessions/index.html +++ b/latest/sessions/index.html @@ -1 +1 @@ - Sessions - Leapp - Docs

Sessions

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

Actions

Method Description
START  Make the temporary credentials available to the provider chain
STOP  Removes the temporary credentials from the provider chain
ROTATE  Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

\ No newline at end of file + Sessions - Leapp - Docs

Sessions

A Session contains all the relevant information to let the dev connect to a cloud provider. Three standard actions should be implemented for each session: start, stop, and rotate.

Actions

Method Description
START  Make the temporary credentials available to the provider chain
STOP  Removes the temporary credentials from the provider chain
ROTATE  Generate new temporary credentials, and substitute the previous ones in the provider chain

The process of setting up Leapp Sessions is managed either manually, for each access method, or through integrations with third-party tools. Leapp stores all the Sessions available to the users locally, inside a configuration file called Workspace.

\ No newline at end of file diff --git a/latest/sitemap.xml b/latest/sitemap.xml index ce7e0b3f9..d7b4b9ba6 100644 --- a/latest/sitemap.xml +++ b/latest/sitemap.xml @@ -4,7 +4,7 @@ https://docs.leapp.cloud/latest/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -16,7 +16,7 @@ https://docs.leapp.cloud/latest/installation/requirements/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -28,7 +28,7 @@ https://docs.leapp.cloud/latest/installation/install-leapp/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -40,7 +40,7 @@ https://docs.leapp.cloud/latest/installation/update-leapp/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -52,7 +52,7 @@ https://docs.leapp.cloud/latest/sessions/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -64,7 +64,7 @@ https://docs.leapp.cloud/latest/integrations/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -76,7 +76,7 @@ https://docs.leapp.cloud/latest/workspaces/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -88,7 +88,7 @@ https://docs.leapp.cloud/latest/cli/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -100,7 +100,7 @@ https://docs.leapp.cloud/latest/cli/scopes/help/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -112,7 +112,7 @@ https://docs.leapp.cloud/latest/cli/scopes/session/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -124,7 +124,7 @@ https://docs.leapp.cloud/latest/cli/scopes/integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -136,7 +136,7 @@ https://docs.leapp.cloud/latest/cli/scopes/profile/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -148,7 +148,7 @@ https://docs.leapp.cloud/latest/cli/scopes/region/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -160,7 +160,7 @@ https://docs.leapp.cloud/latest/cli/scopes/idp-url/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -172,7 +172,7 @@ https://docs.leapp.cloud/latest/cli/scopes/set-workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -184,7 +184,7 @@ https://docs.leapp.cloud/latest/cli/scopes/workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -196,7 +196,7 @@ https://docs.leapp.cloud/latest/cli/scopes/team/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -208,7 +208,7 @@ https://docs.leapp.cloud/latest/cli/scopes/version/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -220,7 +220,7 @@ https://docs.leapp.cloud/latest/configuration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -232,7 +232,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-user/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -244,7 +244,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-role-federated/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -256,7 +256,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-aws-iam-role-chained/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -268,7 +268,7 @@ https://docs.leapp.cloud/latest/configuring-session/configure-localstack/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -280,7 +280,7 @@ https://docs.leapp.cloud/latest/configuring-integration/configure-aws-single-sign-on-integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -292,7 +292,7 @@ https://docs.leapp.cloud/latest/configuring-integration/configure-azure-integration/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -304,7 +304,7 @@ https://docs.leapp.cloud/latest/edit-session/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -316,7 +316,7 @@ https://docs.leapp.cloud/latest/security/intro/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -328,7 +328,7 @@ https://docs.leapp.cloud/latest/security/credentials-generation/aws/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -340,7 +340,7 @@ https://docs.leapp.cloud/latest/security/credential-process/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -352,7 +352,7 @@ https://docs.leapp.cloud/latest/security/credentials-generation/azure/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -364,7 +364,7 @@ https://docs.leapp.cloud/latest/security/system-vault/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -376,7 +376,7 @@ https://docs.leapp.cloud/latest/security/zero-knowledge/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -388,7 +388,7 @@ https://docs.leapp.cloud/latest/built-in-features/aws-ec2-connect/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -400,7 +400,7 @@ https://docs.leapp.cloud/latest/built-in-features/aws-named-profiles/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -412,7 +412,7 @@ https://docs.leapp.cloud/latest/built-in-features/opening-web-console/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -424,7 +424,7 @@ https://docs.leapp.cloud/latest/built-in-features/multi-console/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -436,7 +436,7 @@ https://docs.leapp.cloud/latest/plugins/plugins-introduction/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -448,7 +448,7 @@ https://docs.leapp.cloud/latest/plugins/plugins-development/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -460,79 +460,7 @@ https://docs.leapp.cloud/latest/built-in-features/general-options/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/sign-up/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/sign-in/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/getting-started/lock/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/synchronization/ - 2024-03-29 - daily - - 0.9 - - - - - - - - https://docs.leapp.cloud/latest/leapp-pro/security-and-password/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -544,7 +472,7 @@ https://docs.leapp.cloud/latest/leapp-pro/export-pro-workspace/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -556,7 +484,7 @@ https://docs.leapp.cloud/latest/contributing/get-involved/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -568,7 +496,7 @@ https://docs.leapp.cloud/latest/usefull-scripts/export-profile/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -580,7 +508,7 @@ https://docs.leapp.cloud/latest/troubleshooting/app-data/ - 2024-03-29 + 2024-05-13 daily 0.9 @@ -592,7 +520,7 @@ https://docs.leapp.cloud/latest/troubleshooting/faq/ - 2024-03-29 + 2024-05-13 daily 0.9 diff --git a/latest/sitemap.xml.gz b/latest/sitemap.xml.gz index 9bdc30f0b..3b3e47e61 100644 Binary files a/latest/sitemap.xml.gz and b/latest/sitemap.xml.gz differ diff --git a/latest/troubleshooting/app-data/index.html b/latest/troubleshooting/app-data/index.html index ed0eb2594..11236a11a 100644 --- a/latest/troubleshooting/app-data/index.html +++ b/latest/troubleshooting/app-data/index.html @@ -1,4 +1,4 @@ - Application Data - Leapp - Docs

Application Data

Default Leapp directories

Here the user can find all the directories that Leapp uses directly or indirectly.

Installation path

By default, Leapp is installed in the following locations:

/Applications
+ Application Data - Leapp - Docs      

Application Data

Default Leapp directories

Here the user can find all the directories that Leapp uses directly or indirectly.

Installation path

By default, Leapp is installed in the following locations:

/Applications
 
/opt/Leapp
 
C:\Users\<USER>\AppData\Local\Programs\Leapp
 

Configuration files

By default, Leapp stores the configuration files in the following locations:

~/.Leapp
@@ -11,4 +11,4 @@
 
~/.config/Leapp/logs/log.electronService.log
 
C:\Users\<USER>\AppData\Roaming\Leapp\log.electronService.log
 

Info

Logs are structured in the following way:

[YYYY-MM-DD HH:mm:ss.mmm] [LEVEL] [rendered/system] [COMPONENT] MESSAGE {Useful Object / Stacktrace Err Object}
-

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

\ No newline at end of file +

Warning

Please always add logs to any issue you want to fill whenever possible, so you can help the team identify the problem quickly

\ No newline at end of file diff --git a/latest/troubleshooting/faq/index.html b/latest/troubleshooting/faq/index.html index e91f08386..c96a850f3 100644 --- a/latest/troubleshooting/faq/index.html +++ b/latest/troubleshooting/faq/index.html @@ -1,4 +1,4 @@ - FAQ - Leapp - Docs

FAQ

I'm using the open-source app, do you store my data online?

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

I've got a paid tier, how do you manage my data? Can you access it?

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

I don't feel secure using a built-in window for authentication, can't you use the default browser?

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

How can I find Leapp data in the System Vault?

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

Where do I find the Leapp logs?

Head to the Application data section.

SSM terminal is opening but no session is starting, what can I do?

Just close the terminal and relaunch the SSM command.

AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws
+ FAQ - Leapp - Docs      

FAQ

I'm using the open-source app, do you store my data online?

NO.

The open-source software doesn't transfer, persist, or share anything with other services. All your data is secured and encrypted on your workstation.

Nobody can access it, not even ourselves.

I've got a paid tier, how do you manage my data? Can you access it?

We can't and don't want to see any of your access data.

We need to store your data online to enable some features (syncing, managing other users, etc.) but we implement a Zero-Knowledge encryption system that prevents even ourselves to access your data.

I don't feel secure using a built-in window for authentication, can't you use the default browser?

In the future, Leapp will only use the default browser to authenticate. Right now, this is a compromise to deliver the authentication flow. We already ported the AWS SSO authentication flow on the default browser, and we're working on migrating the other ones as soon as possible.

How can I find Leapp data in the System Vault?

Every key stored by Leapp in the vault is named Leapp. The account name shows the description of the element saved by our software.

Where do I find the Leapp logs?

Head to the Application data section.

SSM terminal is opening but no session is starting, what can I do?

Just close the terminal and relaunch the SSM command.

AWS CLI (or AZ CLI) is installed but Leapp can't find it, what can I do?

Leapp on macOS works in sandbox mode, so some terminal commands must be symlinked in order to work on some installations. Just make a symlink pointing from /usr/local/bin/aws to the actual aws binary or, for AZ CLI, from /usr/local/bin/az to the actual az binary. To create symlinks on macOS, use this command ln -s /any/file/on/the/disk linked-file. The command is called ln. If used with the option -s it will create a symbolic link in the current directory.

Examples:

ln -s /path/to/my/aws /usr/local/bin/aws
 ln -s /path/to/my/az /usr/local/bin/az
 

I use leapp session current but want to see the alias and not the id.

Setting up leappalias command

Follow these steps to set up the leappalias command in your Zsh shell:

  • Create a script file named leappalias.sh using a text editor:
#!/bin/bash
 leapp session current | grep -o "\"alias\":\"[^\"]*" | cut -d '"' -f 4
@@ -7,4 +7,4 @@
 
  • Open your zshrc file using a text editor:
nano ~/.zshrc
 
  • Define an alias for executing the script by adding the following line to the zshrc file:
alias leappalias='/usr/local/bin/leappalias'
 
  • Save the changes and close the zshrc file.

  • Reload the zshrc file in the terminal using the following command:

source ~/.zshrc
-

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

How can I add support to a new SAML 2.0 Identity Provider?

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

\ No newline at end of file +

Once you have completed these steps, you can use the leappalias command in your terminal to extract and display the alias from the output of leapp session current. Credit goes to bspansinQdo.

How can I add support to a new SAML 2.0 Identity Provider?

To add support to a new SAML 2.0 Identity Provider, you have to perform the following steps:

  • create a Fork of the Noovolari/leapp GitHub repository;
  • create a Pull Request and set up your local environment following Install dependencies and build packages section of the DEVELOPMENT.md;
  • add the Identity Provider-specific authentication URL RegEx filter to the Leapp Core authenticationUrlRegexes Map;
  • follow the last part of the Install dependencies and build packages section of the DEVELOPMENT.md to build the solution for both the CLI and the Desktop App;
  • push your changes to your forked repository and propose to merge them to the main repository.

If you need more details about the implementation, please check the How to add a new SAML IdP preset authentication URL section of the DEVELOPMENT.md.

\ No newline at end of file diff --git a/latest/usefull-scripts/export-profile/index.html b/latest/usefull-scripts/export-profile/index.html index 278280f2b..9b217a780 100644 --- a/latest/usefull-scripts/export-profile/index.html +++ b/latest/usefull-scripts/export-profile/index.html @@ -1,4 +1,4 @@ - Useful Scripts - Leapp - Docs

AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {
+ Useful Scripts - Leapp - Docs      

AWS Profile Selector: Simplifying AWS Profile Selection with the Leapp CLI

This script enhances the AWS profile selection process by utilizing the Leapp CLI. It provides a streamlined way to switch between AWS profiles in the command line environment, allowing for easy management of multiple AWS configurations.

function select_and_export_aws_profile() {
     local selected_profile
     selected_profile=$(leapp session list | \
         grep -w 'active' | \
@@ -11,4 +11,4 @@
 }
 
 alias awsp=select_and_export_aws_profile
-

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

\ No newline at end of file +

To use the script, it's important to note that you need to have Leapp installed and running. Leapp is a command-line tool for managing AWS profiles and sessions. Before executing the script, ensure that Leapp is installed on your system and at least one AWS session is active.

Leapp keeps track of your AWS sessions and allows you to switch between different profiles seamlessly. It's a valuable tool for managing multiple AWS accounts and simplifying your workflow. Once Leapp is installed and running, the script utilizes its functionality to retrieve the list of active sessions and display them for selection.

By integrating 'fzf' with Leapp, the script provides an interactive and convenient way to choose the desired AWS profile. With a few keystrokes, you can quickly switch between AWS profiles without manually setting the environment variables each time.

Remember to save the script in your shell configuration file (.bashrc or .zshrc) and restart your terminal or reload the configuration file for the changes to take effect.

In summary, this script simplifies the process of selecting and exporting an AWS profile, making it easier to switch between different AWS configurations when using the command line.

\ No newline at end of file diff --git a/latest/workspaces/index.html b/latest/workspaces/index.html index c936e5112..e0dd5e7f4 100644 --- a/latest/workspaces/index.html +++ b/latest/workspaces/index.html @@ -1 +1 @@ - Workspaces - Leapp - Docs

Workspaces

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

Local

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

Remote

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

Actions

The actions below only applies to Remote workspaces.

Action Description
Sign-in  Connect to a Remote workspace. This action will not switch your Local workspace
Switch  Switch to the selected workspace by clicking on its name in the workspace menu
Lock  Switch back to the Local workspace disabling all the Remote ones
Sign-out  Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

\ No newline at end of file + Workspaces - Leapp - Docs

Workspaces

A Workspace is a global configuration that contains all the relevant information about your Leapp setup (sessions, integrations, app preferences, etc.).

There are two types of workspace: Local and Remote.

Local

A Local workspace is the default workspace that comes with your Leapp installation. It's a private configuration that contains your personal preferences and all sessions and integrations that you created yourself.

A local workspace is associated to a single machine and if you need to migrate your configuration to another one you will have to do it manually.

Alternatively, you can use Remote workspaces.

Remote

A Remote workspace is a Leapp Team configuration set created remotely by a Leapp Team manager.

When you sync a remote workspace, you will receive sessions and integrations automatically, without having to configure them yourself.

A remote workspace is persisted online by using Zero-Knowledge encryption.

You will have access to the same configurations instantly on any machine, by logging in to your Leapp Team account after having been invited by your Leapp Team manager.

Info

Both your local and remote workspaces are saved on your machine as encrypted files inside your /.Leapp directory.

Actions

The actions below only applies to Remote workspaces.

Action Description
Sign-in  Connect to a Remote workspace. This action will not switch your Local workspace
Switch  Switch to the selected workspace by clicking on its name in the workspace menu
Lock  Switch back to the Local workspace disabling all the Remote ones
Sign-out  Sign-out from a Remote workspace removing all your login details

Info

The Lock action also removes the encrypted files associated to your remote workspaces.

\ No newline at end of file