diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..000ab35 --- /dev/null +++ b/404.html @@ -0,0 +1,1037 @@ + + + + + + + + + + + + + + + + + + + + + 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+ +
+ + + + + + + +
+
+ + + +
+
+
+ + + + + + +
+
+
+ + + +
+
+ +

404 - Not found

+ + +
+
+
+ + + + Back to top + + +
+ + + + +
+
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.756773cc.min.js b/assets/javascripts/bundle.756773cc.min.js new file mode 100644 index 0000000..cadeed4 --- /dev/null +++ b/assets/javascripts/bundle.756773cc.min.js @@ -0,0 +1,29 @@ +(()=>{var ta=Object.create;var St=Object.defineProperty;var ra=Object.getOwnPropertyDescriptor;var oa=Object.getOwnPropertyNames,wt=Object.getOwnPropertySymbols,na=Object.getPrototypeOf,ir=Object.prototype.hasOwnProperty,Qr=Object.prototype.propertyIsEnumerable;var Kr=(e,t,r)=>t in e?St(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))ir.call(t,r)&&Kr(e,r,t[r]);if(wt)for(var r of wt(t))Qr.call(t,r)&&Kr(e,r,t[r]);return e};var ia=e=>St(e,"__esModule",{value:!0});var Br=(e,t)=>{var r={};for(var o in e)ir.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&wt)for(var o of wt(e))t.indexOf(o)<0&&Qr.call(e,o)&&(r[o]=e[o]);return r};var Et=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var aa=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of oa(t))!ir.call(e,o)&&o!=="default"&&St(e,o,{get:()=>t[o],enumerable:!(r=ra(t,o))||r.enumerable});return e},Ke=e=>aa(ia(St(e!=null?ta(na(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var Yr=Et((ar,Jr)=>{(function(e,t){typeof ar=="object"&&typeof Jr!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(ar,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={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 s(w){return!!(w&&w!==document&&w.nodeName!=="HTML"&&w.nodeName!=="BODY"&&"classList"in w&&"contains"in w.classList)}function c(w){var We=w.type,Te=w.tagName;return!!(Te==="INPUT"&&a[We]&&!w.readOnly||Te==="TEXTAREA"&&!w.readOnly||w.isContentEditable)}function l(w){w.classList.contains("focus-visible")||(w.classList.add("focus-visible"),w.setAttribute("data-focus-visible-added",""))}function p(w){!w.hasAttribute("data-focus-visible-added")||(w.classList.remove("focus-visible"),w.removeAttribute("data-focus-visible-added"))}function m(w){w.metaKey||w.altKey||w.ctrlKey||(s(r.activeElement)&&l(r.activeElement),o=!0)}function u(w){o=!1}function b(w){!s(w.target)||(o||c(w.target))&&l(w.target)}function v(w){!s(w.target)||(w.target.classList.contains("focus-visible")||w.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),p(w.target))}function d(w){document.visibilityState==="hidden"&&(n&&(o=!0),$())}function $(){document.addEventListener("mousemove",j),document.addEventListener("mousedown",j),document.addEventListener("mouseup",j),document.addEventListener("pointermove",j),document.addEventListener("pointerdown",j),document.addEventListener("pointerup",j),document.addEventListener("touchmove",j),document.addEventListener("touchstart",j),document.addEventListener("touchend",j)}function z(){document.removeEventListener("mousemove",j),document.removeEventListener("mousedown",j),document.removeEventListener("mouseup",j),document.removeEventListener("pointermove",j),document.removeEventListener("pointerdown",j),document.removeEventListener("pointerup",j),document.removeEventListener("touchmove",j),document.removeEventListener("touchstart",j),document.removeEventListener("touchend",j)}function j(w){w.target.nodeName&&w.target.nodeName.toLowerCase()==="html"||(o=!1,z())}document.addEventListener("keydown",m,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",d,!0),$(),r.addEventListener("focus",b,!0),r.addEventListener("blur",v,!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 xo=Et((ls,_t)=>{/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */var Gr,Xr,Zr,eo,to,ro,oo,no,io,Tt,sr,ao,so,co,Be,lo,po,uo,fo,mo,ho,bo,vo,Ot;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(o){e(r(t,r(o)))}):typeof _t=="object"&&typeof _t.exports=="object"?e(r(t,r(_t.exports))):e(r(t));function r(o,n){return o!==t&&(typeof Object.create=="function"?Object.defineProperty(o,"__esModule",{value:!0}):o.__esModule=!0),function(i,a){return o[i]=n?n(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(o,n){o.__proto__=n}||function(o,n){for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(o[i]=n[i])};Gr=function(o,n){if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");t(o,n);function i(){this.constructor=o}o.prototype=n===null?Object.create(n):(i.prototype=n.prototype,new i)},Xr=Object.assign||function(o){for(var n,i=1,a=arguments.length;i=0;p--)(l=o[p])&&(c=(s<3?l(c):s>3?l(n,i,c):l(n,i))||c);return s>3&&c&&Object.defineProperty(n,i,c),c},to=function(o,n){return function(i,a){n(i,a,o)}},ro=function(o,n){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(o,n)},oo=function(o,n,i,a){function s(c){return c instanceof i?c:new i(function(l){l(c)})}return new(i||(i=Promise))(function(c,l){function p(b){try{u(a.next(b))}catch(v){l(v)}}function m(b){try{u(a.throw(b))}catch(v){l(v)}}function u(b){b.done?c(b.value):s(b.value).then(p,m)}u((a=a.apply(o,n||[])).next())})},no=function(o,n){var i={label:0,sent:function(){if(c[0]&1)throw c[1];return c[1]},trys:[],ops:[]},a,s,c,l;return l={next:p(0),throw:p(1),return:p(2)},typeof Symbol=="function"&&(l[Symbol.iterator]=function(){return this}),l;function p(u){return function(b){return m([u,b])}}function m(u){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,s&&(c=u[0]&2?s.return:u[0]?s.throw||((c=s.return)&&c.call(s),0):s.next)&&!(c=c.call(s,u[1])).done)return c;switch(s=0,c&&(u=[u[0]&2,c.value]),u[0]){case 0:case 1:c=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,s=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(c=i.trys,!(c=c.length>0&&c[c.length-1])&&(u[0]===6||u[0]===2)){i=0;continue}if(u[0]===3&&(!c||u[1]>c[0]&&u[1]=o.length&&(o=void 0),{value:o&&o[a++],done:!o}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")},sr=function(o,n){var i=typeof Symbol=="function"&&o[Symbol.iterator];if(!i)return o;var a=i.call(o),s,c=[],l;try{for(;(n===void 0||n-- >0)&&!(s=a.next()).done;)c.push(s.value)}catch(p){l={error:p}}finally{try{s&&!s.done&&(i=a.return)&&i.call(a)}finally{if(l)throw l.error}}return c},ao=function(){for(var o=[],n=0;n1||p(d,$)})})}function p(d,$){try{m(a[d]($))}catch(z){v(c[0][3],z)}}function m(d){d.value instanceof Be?Promise.resolve(d.value.v).then(u,b):v(c[0][2],d)}function u(d){p("next",d)}function b(d){p("throw",d)}function v(d,$){d($),c.shift(),c.length&&p(c[0][0],c[0][1])}},po=function(o){var n,i;return n={},a("next"),a("throw",function(s){throw s}),a("return"),n[Symbol.iterator]=function(){return this},n;function a(s,c){n[s]=o[s]?function(l){return(i=!i)?{value:Be(o[s](l)),done:s==="return"}:c?c(l):l}:c}},uo=function(o){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var n=o[Symbol.asyncIterator],i;return n?n.call(o):(o=typeof Tt=="function"?Tt(o):o[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(c){i[c]=o[c]&&function(l){return new Promise(function(p,m){l=o[c](l),s(p,m,l.done,l.value)})}}function s(c,l,p,m){Promise.resolve(m).then(function(u){c({value:u,done:p})},l)}},fo=function(o,n){return Object.defineProperty?Object.defineProperty(o,"raw",{value:n}):o.raw=n,o};var r=Object.create?function(o,n){Object.defineProperty(o,"default",{enumerable:!0,value:n})}:function(o,n){o.default=n};mo=function(o){if(o&&o.__esModule)return o;var n={};if(o!=null)for(var i in o)i!=="default"&&Object.prototype.hasOwnProperty.call(o,i)&&Ot(n,o,i);return r(n,o),n},ho=function(o){return o&&o.__esModule?o:{default:o}},bo=function(o,n){if(!n.has(o))throw new TypeError("attempted to get private field on non-instance");return n.get(o)},vo=function(o,n,i){if(!n.has(o))throw new TypeError("attempted to set private field on non-instance");return n.set(o,i),i},e("__extends",Gr),e("__assign",Xr),e("__rest",Zr),e("__decorate",eo),e("__param",to),e("__metadata",ro),e("__awaiter",oo),e("__generator",no),e("__exportStar",io),e("__createBinding",Ot),e("__values",Tt),e("__read",sr),e("__spread",ao),e("__spreadArrays",so),e("__spreadArray",co),e("__await",Be),e("__asyncGenerator",lo),e("__asyncDelegator",po),e("__asyncValues",uo),e("__makeTemplateObject",fo),e("__importStar",mo),e("__importDefault",ho),e("__classPrivateFieldGet",bo),e("__classPrivateFieldSet",vo)})});var Rr=Et((gt,jr)=>{/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof gt=="object"&&typeof jr=="object"?jr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof gt=="object"?gt.ClipboardJS=r():t.ClipboardJS=r()})(gt,function(){return function(){var e={134:function(o,n,i){"use strict";i.d(n,{default:function(){return Zi}});var a=i(279),s=i.n(a),c=i(370),l=i.n(c),p=i(817),m=i.n(p);function u(_){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?u=function(h){return typeof h}:u=function(h){return h&&typeof Symbol=="function"&&h.constructor===Symbol&&h!==Symbol.prototype?"symbol":typeof h},u(_)}function b(_,x){if(!(_ instanceof x))throw new TypeError("Cannot call a class as a function")}function v(_,x){for(var h=0;h0&&arguments[0]!==void 0?arguments[0]:{};this.action=h.action,this.container=h.container,this.emitter=h.emitter,this.target=h.target,this.text=h.text,this.trigger=h.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"createFakeElement",value:function(){var h=document.documentElement.getAttribute("dir")==="rtl";this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[h?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return this.fakeElem.style.top="".concat(k,"px"),this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.fakeElem}},{key:"selectFake",value:function(){var h=this,k=this.createFakeElement();this.fakeHandlerCallback=function(){return h.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.container.appendChild(k),this.selectedText=m()(k),this.copyText(),this.removeFake()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=m()(this.target),this.copyText()}},{key:"copyText",value:function(){var h;try{h=document.execCommand(this.action)}catch(k){h=!1}this.handleResult(h)}},{key:"handleResult",value:function(h){this.emitter.emit(h?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var h=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"copy";if(this._action=h,this._action!=="copy"&&this._action!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(h){if(h!==void 0)if(h&&u(h)==="object"&&h.nodeType===1){if(this.action==="copy"&&h.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(this.action==="cut"&&(h.hasAttribute("readonly")||h.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`);this._target=h}else throw new Error('Invalid "target" value, use a valid Element')},get:function(){return this._target}}]),_}(),z=$;function j(_){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?j=function(h){return typeof h}:j=function(h){return h&&typeof Symbol=="function"&&h.constructor===Symbol&&h!==Symbol.prototype?"symbol":typeof h},j(_)}function w(_,x){if(!(_ instanceof x))throw new TypeError("Cannot call a class as a function")}function We(_,x){for(var h=0;h0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=j(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var Z=this;this.listener=l()(I,"click",function(pt){return Z.onClick(pt)})}},{key:"onClick",value:function(I){var Z=I.delegateTarget||I.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new z({action:this.action(Z),target:this.target(Z),text:this.text(Z),container:this.container,trigger:Z,emitter:this})}},{key:"defaultAction",value:function(I){return nr("action",I)}},{key:"defaultTarget",value:function(I){var Z=nr("target",I);if(Z)return document.querySelector(Z)}},{key:"defaultText",value:function(I){return nr("text",I)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Z=typeof I=="string"?[I]:I,pt=!!document.queryCommandSupported;return Z.forEach(function(ea){pt=pt&&!!document.queryCommandSupported(ea)}),pt}}]),h}(s()),Zi=Xi},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 a(s,c){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(c))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(p,m,u,b,v){var d=l.apply(this,arguments);return p.addEventListener(u,d,v),{destroy:function(){p.removeEventListener(u,d,v)}}}function c(p,m,u,b,v){return typeof p.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof p=="string"&&(p=document.querySelectorAll(p)),Array.prototype.map.call(p,function(d){return s(d,m,u,b,v)}))}function l(p,m,u,b){return function(v){v.delegateTarget=a(v.target,m),v.delegateTarget&&b.call(p,v)}}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 a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[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 a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function c(u,b,v){if(!u&&!b&&!v)throw new Error("Missing required arguments");if(!a.string(b))throw new TypeError("Second argument must be a String");if(!a.fn(v))throw new TypeError("Third argument must be a Function");if(a.node(u))return l(u,b,v);if(a.nodeList(u))return p(u,b,v);if(a.string(u))return m(u,b,v);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function l(u,b,v){return u.addEventListener(b,v),{destroy:function(){u.removeEventListener(b,v)}}}function p(u,b,v){return Array.prototype.forEach.call(u,function(d){d.addEventListener(b,v)}),{destroy:function(){Array.prototype.forEach.call(u,function(d){d.removeEventListener(b,v)})}}}function m(u,b,v){return s(document.body,u,b,v)}o.exports=c},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),l=document.createRange();l.selectNodeContents(i),c.removeAllRanges(),c.addRange(l),a=c.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var c=this;function l(){c.off(i,l),a.apply(s,arguments)}return l._=a,this.on(i,l,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),c=0,l=s.length;for(c;c{/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */"use strict";var Ka=/["'&<>]/;yi.exports=Ba;function Ba(e){var t=""+e,r=Ka.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i0},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=o.hasError,i=o.isStopped,a=o.observers;return n||i?cr:(a.push(r),new ae(function(){return Oe(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new A;return r.source=this,r},t.create=function(r,o){return new Ho(r,o)},t}(A);var Ho=function(e){G(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:cr},t}(T);var mt={now:function(){return(mt.delegate||Date).now()},delegate:void 0};var dt=function(e){G(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=mt);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,a=o._infiniteTimeWindow,s=o._timestampProvider,c=o._windowTime;n||(i.push(r),!a&&i.push(s.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,a=n._buffer,s=a.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Ge.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){if(n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);r.actions.length===0&&(Ge.cancelAnimationFrame(o),r._scheduled=void 0)},t}(jt);var Fo=function(e){G(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0,this._scheduled=void 0;var o=this.actions,n,i=-1;r=r||o.shift();var a=o.length;do if(n=r.execute(r.state,r.delay))break;while(++i=2,!0))}function ie(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new T}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,c=s===void 0?!0:s;return function(l){var p=null,m=null,u=null,b=0,v=!1,d=!1,$=function(){m==null||m.unsubscribe(),m=null},z=function(){$(),p=u=null,v=d=!1},j=function(){var w=p;z(),w==null||w.unsubscribe()};return g(function(w,We){b++,!d&&!v&&$();var Te=u=u!=null?u:r();We.add(function(){b--,b===0&&!d&&!v&&(m=Tr(j,c))}),Te.subscribe(We),p||(p=new ft({next:function(Qe){return Te.next(Qe)},error:function(Qe){d=!0,$(),m=Tr(z,n,Qe),Te.error(Qe)},complete:function(){v=!0,$(),m=Tr(z,a),Te.complete()}}),ye(w).subscribe(p))})(l)}}function Tr(e,t){for(var r=[],o=2;ot==="focus"),N(e===De()))}var on=new T,ja=_e(()=>R(new ResizeObserver(e=>{for(let t of e)on.next(t)}))).pipe(O(e=>J.pipe(N(e)).pipe(F(()=>e.disconnect()))),re(1));function Re(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function Fe(e){return ja.pipe(L(t=>t.observe(e)),O(t=>on.pipe(M(({target:r})=>r===e),F(()=>t.unobserve(e)),f(()=>Re(e)))),N(Re(e)))}function nn(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ra(e){return W(E(e,"scroll"),E(window,"resize")).pipe(f(()=>nn(e)),N(nn(e)))}function an(e,t=16){return Ra(e).pipe(f(({y:r})=>{let o=Re(e),n=Bt(e);return r>=n.height-o.height-t}),D())}function sn(e){if(e instanceof HTMLInputElement)e.select();else throw new Error("Not implemented")}var Jt={drawer:he("[data-md-toggle=drawer]"),search:he("[data-md-toggle=search]")};function cn(e){return Jt[e].checked}function Ie(e,t){Jt[e].checked!==t&&Jt[e].click()}function Yt(e){let t=Jt[e];return E(t,"change").pipe(f(()=>t.checked),N(t.checked))}function Fa(e){switch(e.tagName){case"INPUT":case"SELECT":case"TEXTAREA":return!0;default:return e.isContentEditable}}function ln(){return E(window,"keydown").pipe(M(e=>!(e.metaKey||e.ctrlKey)),f(e=>({mode:cn("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),M(({mode:e})=>{if(e==="global"){let t=De();if(typeof t!="undefined")return!Fa(t)}return!0}),ie())}function Pe(){return new URL(location.href)}function pn(e){location.href=e.href}function un(){return new T}function fn(){return location.hash.substring(1)}function mn(e){let t=it("a");t.href=e,t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ia(){return E(window,"hashchange").pipe(f(fn),N(fn()),M(e=>e.length>0),ie())}function dn(){return Ia().pipe(O(e=>R(se(`[id="${e}"]`))))}function xt(e){let t=matchMedia(e);return Qt(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function hn(){return E(window,"beforeprint").pipe(oe(void 0))}function Cr(e,t){return e.pipe(O(r=>r?t():J))}function Gt(e,t={credentials:"same-origin"}){return ye(fetch(`${e}`,t)).pipe(M(r=>r.status===200))}function we(e,t){return Gt(e,t).pipe(O(r=>r.json()),re(1))}function bn(e,t){let r=new DOMParser;return Gt(e,t).pipe(O(o=>o.text()),f(o=>r.parseFromString(o,"text/xml")),re(1))}function vn(){return{x:Math.max(0,pageXOffset),y:Math.max(0,pageYOffset)}}function Hr({x:e,y:t}){window.scrollTo(e||0,t||0)}function xn(){return W(E(window,"scroll",{passive:!0}),E(window,"resize",{passive:!0})).pipe(f(vn),N(vn()))}function gn(){return{width:innerWidth,height:innerHeight}}function yn(){return E(window,"resize",{passive:!0}).pipe(f(gn),N(gn()))}function Sn(){return K([xn(),yn()]).pipe(f(([e,t])=>({offset:e,size:t})),re(1))}function Xt(e,{viewport$:t,header$:r}){let o=t.pipe(V("size")),n=K([o,r]).pipe(f(()=>({x:e.offsetLeft,y:e.offsetTop})));return K([r,t,n]).pipe(f(([{height:i},{offset:a,size:s},{x:c,y:l}])=>({offset:{x:a.x-c,y:a.y-l+i},size:s})))}function wn(e,{tx$:t}){let r=E(e,"message").pipe(f(({data:o})=>o));return t.pipe(Lr(()=>r,{leading:!0,trailing:!0}),L(o=>e.postMessage(o)),_r(r),ie())}var Pa=he("#__config"),at=JSON.parse(Pa.textContent);at.base=`${new URL(at.base,Pe())}`;function ce(){return at}function Ae(e){return at.features.includes(e)}function Y(e,t){return typeof t!="undefined"?at.translations[e].replace("#",t.toString()):at.translations[e]}function Ee(e,t=document){return he(`[data-md-component=${e}]`,t)}function ne(e,t=document){return B(`[data-md-component=${e}]`,t)}var ai=Ke(Rr());function En(e,t=0){e.setAttribute("tabindex",t.toString())}function Tn(e){e.removeAttribute("tabindex")}function On(e,t){e.setAttribute("data-md-state","lock"),e.style.top=`-${t}px`}function _n(e){let t=-1*parseInt(e.style.top,10);e.removeAttribute("data-md-state"),e.style.top="",t&&window.scrollTo(0,t)}function Mn(e,t){e.setAttribute("data-md-state",t)}function An(e){e.removeAttribute("data-md-state")}function Ln(e,t){e.classList.toggle("md-nav__link--active",t)}function kn(e){e.classList.remove("md-nav__link--active")}function Cn(e,t){e.firstElementChild.innerHTML=t}function Hn(e,t){e.setAttribute("data-md-state",t)}function jn(e){e.removeAttribute("data-md-state")}function Rn(e,t){e.setAttribute("data-md-state",t)}function Fn(e){e.removeAttribute("data-md-state")}function In(e,t){e.setAttribute("data-md-state",t)}function Pn(e){e.removeAttribute("data-md-state")}function $n(e,t){e.placeholder=t}function Wn(e){e.placeholder=Y("search.placeholder")}function Un(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)Un(e,r)}function U(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="boolean"?o.setAttribute(n,t[n]):t[n]&&o.setAttribute(n,"");for(let n of r)Un(o,n);return o}function Vn(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function Zt(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Nn(e,t){switch(t){case 0:e.textContent=Y("search.result.none");break;case 1:e.textContent=Y("search.result.one");break;default:e.textContent=Y("search.result.other",Zt(t))}}function Fr(e){e.textContent=Y("search.result.placeholder")}function Dn(e,t){e.appendChild(t)}function zn(e){e.innerHTML=""}function qn(e,t){e.style.top=`${t}px`}function Qn(e){e.style.top=""}function Kn(e,t){let r=e.firstElementChild;r.style.height=`${t-2*r.offsetTop}px`}function Bn(e){let t=e.firstElementChild;t.style.height=""}function Jn(e,t){e.lastElementChild.appendChild(t)}function Yn(e,t){e.lastElementChild.setAttribute("data-md-state",t)}function Gn(e,t){e.setAttribute("data-md-state",t)}function Ir(e){e.removeAttribute("data-md-state")}function Xn(e,t){e.setAttribute("data-md-state",t)}function Pr(e){e.removeAttribute("data-md-state")}function Zn(e,t){e.style.top=`${t}px`}function ei(e){e.style.top=""}function ti(e){return U("button",{class:"md-clipboard md-icon",title:Y("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var qe;(function(r){r[r.TEASER=1]="TEASER",r[r.PARENT=2]="PARENT"})(qe||(qe={}));function $r(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(a=>!e.terms[a]).map(a=>[U("del",null,a)," "]).flat().slice(0,-1),i=new URL(e.location);return Ae("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,a])=>a).reduce((a,[s])=>`${a} ${s}`.trim(),"")),U("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},U("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&U("div",{class:"md-search-result__icon md-icon"}),U("h1",{class:"md-search-result__title"},e.title),o>0&&e.text.length>0&&U("p",{class:"md-search-result__teaser"},Vn(e.text,320)),o>0&&n.length>0&&U("p",{class:"md-search-result__terms"},Y("search.result.term.missing"),": ",n)))}function ri(e){let t=e[0].score,r=[...e],o=r.findIndex(l=>!l.location.includes("#")),[n]=r.splice(o,1),i=r.findIndex(l=>l.score$r(l,1)),...s.length?[U("details",{class:"md-search-result__more"},U("summary",{tabIndex:-1},s.length>0&&s.length===1?Y("search.result.more.one"):Y("search.result.more.other",s.length)),s.map(l=>$r(l,1)))]:[]];return U("li",{class:"md-search-result__item"},c)}function oi(e){return U("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>U("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?Zt(r):r)))}function ni(e){return U("div",{class:"md-typeset__scrollwrap"},U("div",{class:"md-typeset__table"},e))}function $a(e){let t=ce(),r=new URL(`../${e.version}/`,t.base);return U("li",{class:"md-version__item"},U("a",{href:r.toString(),class:"md-version__link"},e.title))}function ii(e){let t=ce(),[,r]=t.base.match(/([^/]+)\/?$/),o=e.find(({version:n,aliases:i})=>n===r||i.includes(r))||e[0];return U("div",{class:"md-version"},U("button",{class:"md-version__current","aria-label":Y("select.version.title")},o.title),U("ul",{class:"md-version__list"},e.map($a)))}var Wa=0;function Ua(e,{viewport$:t}){let r=R(e).pipe(O(o=>{let n=o.closest("[data-tabs]");return n instanceof HTMLElement?W(...B("input",n).map(i=>E(i,"change"))):J}));return W(t.pipe(V("size")),r).pipe(f(()=>{let o=Re(e);return{scroll:Bt(e).width>o.width}}),V("scroll"))}function si(e,t){let r=new T;if(r.pipe(ue(xt("(hover)"))).subscribe(([{scroll:o},n])=>{o&&n?En(e):Tn(e)}),ai.default.isSupported()){let o=e.closest("pre");o.id=`__code_${Wa++}`,o.insertBefore(ti(o.id),e)}return Ua(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function Va(e,{target$:t,print$:r}){return t.pipe(f(o=>o.closest("details:not([open])")),M(o=>e===o),Ne(r),oe(e))}function ci(e,t){let r=new T;return r.subscribe(()=>{e.setAttribute("open",""),e.scrollIntoView()}),Va(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),oe({ref:e}))}var li=it("table");function pi(e){return ze(e,li),ze(li,ni(e)),R({ref:e})}function ui(e,{target$:t,viewport$:r,print$:o}){return W(...B("pre > code",e).map(n=>si(n,{viewport$:r})),...B("table:not([class])",e).map(n=>pi(n)),...B("details",e).map(n=>ci(n,{target$:t,print$:o})))}function Na(e,{alert$:t}){return t.pipe(O(r=>W(R(!0),R(!1).pipe(Me(2e3))).pipe(f(o=>({message:r,open:o})))))}function fi(e,t){let r=new T;return r.pipe(Q(X)).subscribe(({message:o,open:n})=>{Cn(e,o),n?Hn(e,"open"):jn(e)}),Na(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function Da({viewport$:e}){if(!Ae("header.autohide"))return R(!1);let t=e.pipe(f(({offset:{y:n}})=>n),xe(2,1),f(([n,i])=>[nMath.abs(i-n.y)>100),f(([,[n]])=>n),D()),o=Yt("search");return K([e,o]).pipe(f(([{offset:n},i])=>n.y>400&&!i),D(),O(n=>n?r:R(!1)),N(!1))}function mi(e,t){return _e(()=>{let r=getComputedStyle(e);return R(r.position==="sticky"||r.position==="-webkit-sticky")}).pipe(ot(Fe(e),Da(t)),f(([r,{height:o},n])=>({height:r?o:0,sticky:r,hidden:n})),D((r,o)=>r.sticky===o.sticky&&r.height===o.height&&r.hidden===o.hidden),re(1))}function di(e,{header$:t,main$:r}){let o=new T;return o.pipe(V("active"),ot(t),Q(X)).subscribe(([{active:n},{hidden:i}])=>{n?Rn(e,i?"hidden":"shadow"):Fn(e)}),r.subscribe(n=>o.next(n)),t.pipe(f(n=>P({ref:e},n)))}function za(e,{viewport$:t,header$:r}){return Xt(e,{header$:r,viewport$:t}).pipe(f(({offset:{y:o}})=>{let{height:n}=Re(e);return{active:o>=n}}),V("active"))}function hi(e,t){let r=new T;r.pipe(Q(X)).subscribe(({active:n})=>{n?In(e,"active"):Pn(e)});let o=se("article h1");return typeof o=="undefined"?J:za(o,t).pipe(L(n=>r.next(n)),F(()=>r.complete()),f(n=>P({ref:e},n)))}function bi(e,{viewport$:t,header$:r}){let o=r.pipe(f(({height:i})=>i),D()),n=o.pipe(O(()=>Fe(e).pipe(f(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),V("bottom"))));return K([o,n,t]).pipe(f(([i,{top:a,bottom:s},{offset:{y:c},size:{height:l}}])=>(l=Math.max(0,l-Math.max(0,a-c,i)-Math.max(0,l+c-s)),{offset:a-i,height:l,active:a-i<=c})),D((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function qa(e){let t=localStorage.getItem(__prefix("__palette")),r=JSON.parse(t)||{index:e.findIndex(n=>matchMedia(n.getAttribute("data-md-color-media")).matches)},o=R(...e).pipe(te(n=>E(n,"change").pipe(oe(n))),N(e[Math.max(0,r.index)]),f(n=>({index:e.indexOf(n),color:{scheme:n.getAttribute("data-md-color-scheme"),primary:n.getAttribute("data-md-color-primary"),accent:n.getAttribute("data-md-color-accent")}})),re(1));return o.subscribe(n=>{localStorage.setItem(__prefix("__palette"),JSON.stringify(n))}),o}function vi(e){let t=new T;t.subscribe(o=>{for(let[n,i]of Object.entries(o.color))typeof i=="string"&&document.body.setAttribute(`data-md-color-${n}`,i);for(let n=0;nt.next(o)),F(()=>t.complete()),f(o=>P({ref:e},o)))}var Wr=Ke(Rr());function xi({alert$:e}){Wr.default.isSupported()&&new A(t=>{new Wr.default("[data-clipboard-target], [data-clipboard-text]").on("success",r=>t.next(r))}).subscribe(()=>e.next(Y("clipboard.copied")))}function Qa(e){if(e.length<2)return e;let[t,r]=e.sort((i,a)=>i.length-a.length).map(i=>i.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;let n=ce();return e.map(i=>i.replace(t.slice(0,o),n.base))}function gi({document$:e,location$:t,viewport$:r}){let o=ce();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",E(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let n=se("link[rel=icon]");typeof n!="undefined"&&(n.href=n.href);let i=bn(new URL("sitemap.xml",o.base)).pipe(f(l=>Qa(B("loc",l).map(p=>p.textContent))),O(l=>E(document.body,"click").pipe(M(p=>!p.metaKey&&!p.ctrlKey),O(p=>{if(p.target instanceof Element){let m=p.target.closest("a");if(m&&!m.target){let u=new URL(m.href);if(u.search="",u.hash="",u.pathname!==location.pathname&&l.includes(u.toString()))return p.preventDefault(),R({url:new URL(m.href)})}}return J}))),ie()),a=E(window,"popstate").pipe(M(l=>l.state!==null),f(l=>({url:new URL(location.href),offset:l.state})),ie());W(i,a).pipe(D((l,p)=>l.url.href===p.url.href),f(({url:l})=>l)).subscribe(t);let s=t.pipe(V("pathname"),O(l=>Gt(l.href).pipe(rt(()=>(pn(l),J)))),ie());i.pipe(nt(s)).subscribe(({url:l})=>{history.pushState({},"",`${l}`)});let c=new DOMParser;s.pipe(O(l=>l.text()),f(l=>c.parseFromString(l,"text/html"))).subscribe(e),e.pipe(Kt(1)).subscribe(l=>{for(let p of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=logo], .md-logo","[data-md-component=skip]"]){let m=se(p),u=se(p,l);typeof m!="undefined"&&typeof u!="undefined"&&ze(m,u)}}),e.pipe(Kt(1),f(()=>Ee("container")),O(l=>R(...B("script",l))),gr(l=>{let p=it("script");if(l.src){for(let m of l.getAttributeNames())p.setAttribute(m,l.getAttribute(m));return ze(l,p),new A(m=>{p.onload=()=>m.complete()})}else return p.textContent=l.textContent,ze(l,p),ve})).subscribe(),W(i,a).pipe(nt(e)).subscribe(({url:l,offset:p})=>{l.hash&&!p?mn(l.hash):Hr(p||{y:0})}),r.pipe(Or(i),yr(250),V("offset")).subscribe(({offset:l})=>{history.replaceState(l,"")}),W(i,a).pipe(xe(2,1),M(([l,p])=>l.url.pathname===p.url.pathname),f(([,l])=>l)).subscribe(({offset:l})=>{Hr(l||{y:0})})}var Ja=Ke(Ur());var Si=Ke(Ur());function Vr(e,t){let r=new RegExp(e.separator,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,Si.default)(a):a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function wi(e){return e.split(/"([^"]+)"/g).map((t,r)=>r&1?t.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):t).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}var Le;(function(n){n[n.SETUP=0]="SETUP",n[n.READY=1]="READY",n[n.QUERY=2]="QUERY",n[n.RESULT=3]="RESULT"})(Le||(Le={}));function st(e){return e.type===1}function Ei(e){return e.type===2}function ct(e){return e.type===3}function Ya({config:e,docs:t,index:r}){e.lang.length===1&&e.lang[0]==="en"&&(e.lang=[Y("search.config.lang")]),e.separator==="[\\s\\-]+"&&(e.separator=Y("search.config.separator"));let n={pipeline:Y("search.config.pipeline").split(/\s*,\s*/).filter(Boolean),suggestions:Ae("search.suggest")};return{config:e,docs:t,index:r,options:n}}function Ti(e,t){let r=ce(),o=new Worker(e),n=new T,i=wn(o,{tx$:n}).pipe(f(a=>{if(ct(a))for(let s of a.data.items)for(let c of s)c.location=`${new URL(c.location,r.base)}`;return a}),ie());return ye(t).pipe(f(a=>({type:Le.SETUP,data:Ya(a)}))).subscribe(n.next.bind(n)),{tx$:n,rx$:i}}function Oi(){let e=ce();we(new URL("../versions.json",e.base)).subscribe(t=>{he(".md-header__topic").appendChild(ii(t))})}function Ga(e,{rx$:t}){let r=(__search==null?void 0:__search.transform)||wi,o=rn(e),n=W(E(e,"keyup"),E(e,"focus").pipe(Me(1))).pipe(f(()=>r(e.value)),D()),i=Pe();return i.searchParams.has("q")&&(Ie("search",!0),t.pipe(M(st),de(1)).subscribe(()=>{e.value=i.searchParams.get("q"),ge(e)})),K([n,o]).pipe(f(([a,s])=>({value:a,focus:s})))}function _i(e,{tx$:t,rx$:r}){let o=new T;return o.pipe(V("value"),f(({value:n})=>({type:Le.QUERY,data:n}))).subscribe(t.next.bind(t)),o.pipe(V("focus")).subscribe(({focus:n})=>{n?(Ie("search",n),$n(e,"")):Wn(e)}),E(e.form,"reset").pipe(Mr(o.pipe(wr(1)))).subscribe(()=>ge(e)),Ga(e,{tx$:t,rx$:r}).pipe(L(n=>o.next(n)),F(()=>o.complete()),f(n=>P({ref:e},n)))}function Mi(e,{rx$:t},{query$:r}){let o=new T,n=an(e.parentElement).pipe(M(Boolean)),i=he(":scope > :first-child",e),a=he(":scope > :last-child",e);return t.pipe(M(st),de(1)).subscribe(()=>{Fr(i)}),o.pipe(Q(X),ue(r)).subscribe(([{items:c},{value:l}])=>{l?Nn(i,c.length):Fr(i)}),o.pipe(Q(X),L(()=>zn(a)),O(({items:c})=>W(R(...c.slice(0,10)),R(...c.slice(10)).pipe(xe(4),kr(n),O(([l])=>R(...l)))))).subscribe(c=>{Dn(a,ri(c))}),t.pipe(M(ct),f(({data:c})=>c)).pipe(L(c=>o.next(c)),F(()=>o.complete()),f(c=>P({ref:e},c)))}function Xa(e,{query$:t}){return t.pipe(f(({value:r})=>{let o=Pe();return o.hash="",o.searchParams.delete("h"),o.searchParams.set("q",r),{url:o}}))}function Ai(e,t){let r=new T;return r.subscribe(({url:o})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${o}`}),E(e,"click").subscribe(o=>o.preventDefault()),Xa(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function Li(e,{rx$:t},{keyboard$:r}){let o=new T,n=Ee("search-query"),i=E(n,"keydown").pipe(Q(Ce),f(()=>n.value),D());return o.pipe(ot(i),f(([{suggestions:s},c])=>{let l=c.split(/([\s-]+)/);if((s==null?void 0:s.length)&&l[l.length-1]){let p=s[s.length-1];p.startsWith(l[l.length-1])&&(l[l.length-1]=p)}else l.length=0;return l})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(M(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(M(ct),f(({data:s})=>s)).pipe(L(s=>o.next(s)),F(()=>o.complete()),f(()=>({ref:e})))}function ki(e,{index$:t,keyboard$:r}){let o=ce();try{let n=(__search==null?void 0:__search.worker)||o.search,i=Ti(n,t),a=Ee("search-query",e),s=Ee("search-result",e),{tx$:c,rx$:l}=i;c.pipe(M(Ei),nt(l.pipe(M(st),de(1)))).subscribe(c.next.bind(c)),r.pipe(M(({mode:u})=>u==="search")).subscribe(u=>{let b=De();switch(u.type){case"Enter":if(b===a){let v=new Map;for(let d of B(":first-child [href]",s)){let $=d.firstElementChild;v.set(d,parseFloat($.getAttribute("data-md-score")))}if(v.size){let[[d]]=[...v].sort(([,$],[,z])=>z-$);d.click()}u.claim()}break;case"Escape":case"Tab":Ie("search",!1),ge(a,!1);break;case"ArrowUp":case"ArrowDown":if(typeof b=="undefined")ge(a);else{let v=[a,...B(":not(details) > [href], summary, details[open] [href]",s)],d=Math.max(0,(Math.max(0,v.indexOf(b))+v.length+(u.type==="ArrowUp"?-1:1))%v.length);ge(v[d])}u.claim();break;default:a!==De()&&ge(a)}}),r.pipe(M(({mode:u})=>u==="global")).subscribe(u=>{switch(u.type){case"f":case"s":case"/":ge(a),sn(a),u.claim();break}});let p=_i(a,i),m=Mi(s,i,{query$:p});return W(p,m).pipe(Ne(...ne("search-share",e).map(u=>Ai(u,{query$:p})),...ne("search-suggest",e).map(u=>Li(u,i,{keyboard$:r}))))}catch(n){return e.hidden=!0,J}}function Ci(e,{index$:t,location$:r}){return K([t,r.pipe(N(Pe()),M(o=>o.searchParams.has("h")))]).pipe(f(([o,n])=>Vr(o.config,!0)(n.searchParams.get("h"))),f(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)==null?void 0:a.offsetHeight){let c=s.textContent,l=o(c);l.length>c.length&&n.set(s,l)}for(let[s,c]of n){let{childNodes:l}=U("span",null,c);s.replaceWith(...Array.from(l))}return{ref:e,nodes:n}}))}function Za(e,{viewport$:t,main$:r}){let o=e.parentElement.offsetTop-e.parentElement.parentElement.offsetTop;return K([r,t]).pipe(f(([{offset:n,height:i},{offset:{y:a}}])=>(i=i+Math.min(o,Math.max(0,a-n))-o,{height:i,locked:a>=n+o})),D((n,i)=>n.height===i.height&&n.locked===i.locked))}function Nr(e,o){var n=o,{header$:t}=n,r=Br(n,["header$"]);let i=new T;return i.pipe(Q(X),ue(t)).subscribe({next([{height:a},{height:s}]){Kn(e,a),qn(e,s)},complete(){Qn(e),Bn(e)}}),Za(e,r).pipe(L(a=>i.next(a)),F(()=>i.complete()),f(a=>P({ref:e},a)))}function Hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return vt(we(`${r}/releases/latest`).pipe(f(o=>({version:o.tag_name})),Ve({})),we(r).pipe(f(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(f(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/repos/${e}`;return we(r).pipe(f(o=>({repositories:o.public_repos})),Ve({}))}}function ji(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return we(r).pipe(f(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))}function Ri(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,o]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Hi(r,o);case"gitlab":let[,n,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return ji(n,i);default:return J}}var es;function ts(e){return es||(es=_e(()=>{let t=sessionStorage.getItem(__prefix("__source"));if(t)return R(JSON.parse(t));{let r=Ri(e.href);return r.subscribe(o=>{try{sessionStorage.setItem(__prefix("__source"),JSON.stringify(o))}catch(n){}}),r}}).pipe(rt(()=>J),M(t=>Object.keys(t).length>0),f(t=>({facts:t})),re(1)))}function Fi(e){let t=new T;return t.subscribe(({facts:r})=>{Jn(e,oi(r)),Yn(e,"done")}),ts(e).pipe(L(r=>t.next(r)),F(()=>t.complete()),f(r=>P({ref:e},r)))}function rs(e,{viewport$:t,header$:r}){return Fe(document.body).pipe(O(()=>Xt(e,{header$:r,viewport$:t})),f(({offset:{y:o}})=>({hidden:o>=10})),V("hidden"))}function Ii(e,t){let r=new T;return r.pipe(Q(X)).subscribe({next({hidden:o}){o?Gn(e,"hidden"):Ir(e)},complete(){Ir(e)}}),rs(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function os(e,{viewport$:t,header$:r}){let o=new Map;for(let a of e){let s=decodeURIComponent(a.hash.substring(1)),c=se(`[id="${s}"]`);typeof c!="undefined"&&o.set(a,c)}let n=r.pipe(f(a=>24+a.height));return Fe(document.body).pipe(V("height"),f(()=>{let a=[];return[...o].reduce((s,[c,l])=>{for(;a.length&&o.get(a[a.length-1]).tagName>=l.tagName;)a.pop();let p=l.offsetTop;for(;!p&&l.parentElement;)l=l.parentElement,p=l.offsetTop;return s.set([...a=[...a,c]].reverse(),p)},new Map)}),f(a=>new Map([...a].sort(([,s],[,c])=>s-c))),O(a=>K([n,t]).pipe(Er(([s,c],[l,{offset:{y:p}}])=>{for(;c.length;){let[,m]=c[0];if(m-l=p)c=[s.pop(),...c];else break}return[s,c]},[[],[...a]]),D((s,c)=>s[0]===c[0]&&s[1]===c[1])))).pipe(f(([a,s])=>({prev:a.map(([c])=>c),next:s.map(([c])=>c)})),N({prev:[],next:[]}),xe(2,1),f(([a,s])=>a.prev.length{for(let[a]of i)kn(a),An(a);for(let[a,[s]]of n.entries())Ln(s,a===n.length-1),Mn(s,"blur")});let o=B("[href^=\\#]",e);return os(o,t).pipe(L(n=>r.next(n)),F(()=>r.complete()),f(n=>P({ref:e},n)))}function ns(e,{viewport$:t,main$:r}){let o=t.pipe(f(({offset:{y:i}})=>i),xe(2,1),f(([i,a])=>i>a&&a),D()),n=r.pipe(V("active"));return K([n,o]).pipe(f(([{active:i},a])=>({hidden:!(i&&a)})),D((i,a)=>i.hidden===a.hidden))}function $i(e,{viewport$:t,header$:r,main$:o}){let n=new T;return n.pipe(Q(X),ue(r.pipe(V("height")))).subscribe({next([{hidden:i},{height:a}]){Zn(e,a+16),i?(Xn(e,"hidden"),ge(e,!1)):Pr(e)},complete(){ei(e),Pr(e)}}),ns(e,{viewport$:t,header$:r,main$:o}).pipe(L(i=>n.next(i)),F(()=>n.complete()),f(i=>P({ref:e},i)))}function Wi({document$:e,tablet$:t}){e.pipe(O(()=>R(...B("[data-md-state=indeterminate]"))),L(r=>{r.indeterminate=!0,r.checked=!1}),te(r=>E(r,"change").pipe(Ar(()=>r.hasAttribute("data-md-state")),oe(r))),ue(t)).subscribe(([r,o])=>{r.removeAttribute("data-md-state"),o&&(r.checked=!1)})}function is(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ui({document$:e}){e.pipe(O(()=>R(...B("[data-md-scrollfix]"))),L(t=>t.removeAttribute("data-md-scrollfix")),M(is),te(t=>E(t,"touchstart").pipe(oe(t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Vi({viewport$:e,tablet$:t}){K([Yt("search"),t]).pipe(f(([r,o])=>r&&!o),O(r=>R(r).pipe(Me(r?400:100),Q(X))),ue(e)).subscribe(([r,{offset:{y:o}}])=>{r?On(document.body,o):_n(document.body)})}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var lt=tn(),er=un(),Dr=dn(),zr=ln(),fe=Sn(),tr=xt("(min-width: 960px)"),Ni=xt("(min-width: 1220px)"),Di=hn(),zi=ce(),qi=document.forms.namedItem("search")?(__search==null?void 0:__search.index)||we(new URL("search/search_index.json",zi.base)):J,qr=new T;xi({alert$:qr});Ae("navigation.instant")&&gi({document$:lt,location$:er,viewport$:fe});var Ki;((Ki=zi.version)==null?void 0:Ki.provider)==="mike"&&Oi();W(er,Dr).pipe(Me(125)).subscribe(()=>{Ie("drawer",!1),Ie("search",!1)});zr.pipe(M(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=se("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=se("[href][rel=next]");typeof r!="undefined"&&r.click();break}});Wi({document$:lt,tablet$:tr});Ui({document$:lt});Vi({viewport$:fe,tablet$:tr});var $e=mi(Ee("header"),{viewport$:fe}),rr=lt.pipe(f(()=>Ee("main")),O(e=>bi(e,{viewport$:fe,header$:$e})),re(1)),as=W(...ne("dialog").map(e=>fi(e,{alert$:qr})),...ne("header").map(e=>di(e,{viewport$:fe,header$:$e,main$:rr})),...ne("palette").map(e=>vi(e)),...ne("search").map(e=>ki(e,{index$:qi,keyboard$:zr})),...ne("source").map(e=>Fi(e))),ss=_e(()=>W(...ne("content").map(e=>ui(e,{target$:Dr,viewport$:fe,print$:Di})),...ne("content").map(e=>Ae("search.highlight")?Ci(e,{index$:qi,location$:er}):J),...ne("header-title").map(e=>hi(e,{viewport$:fe,header$:$e})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Cr(Ni,()=>Nr(e,{viewport$:fe,header$:$e,main$:rr})):Cr(tr,()=>Nr(e,{viewport$:fe,header$:$e,main$:rr}))),...ne("tabs").map(e=>Ii(e,{viewport$:fe,header$:$e})),...ne("toc").map(e=>Pi(e,{viewport$:fe,header$:$e})),...ne("top").map(e=>$i(e,{viewport$:fe,header$:$e,main$:rr})))),Qi=lt.pipe(O(()=>ss),Ne(as),re(1));Qi.subscribe();window.document$=lt;window.location$=er;window.target$=Dr;window.keyboard$=zr;window.viewport$=fe;window.tablet$=tr;window.screen$=Ni;window.print$=Di;window.alert$=qr;window.component$=Qi;})(); +//# sourceMappingURL=bundle.756773cc.min.js.map + diff --git a/assets/javascripts/bundle.756773cc.min.js.map b/assets/javascripts/bundle.756773cc.min.js.map new file mode 100644 index 0000000..4310577 --- /dev/null +++ b/assets/javascripts/bundle.756773cc.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/rxjs/node_modules/tslib/tslib.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/modules/index.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/caughtSchedule.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/fromArray.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/concatMap.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/switchMapTo.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/assets/javascripts/browser/document/index.ts", "src/assets/javascripts/browser/element/_/index.ts", "src/assets/javascripts/browser/element/focus/index.ts", "src/assets/javascripts/browser/element/size/index.ts", "src/assets/javascripts/browser/element/offset/index.ts", "src/assets/javascripts/browser/element/selection/index.ts", "src/assets/javascripts/browser/toggle/index.ts", "src/assets/javascripts/browser/keyboard/index.ts", "src/assets/javascripts/browser/location/_/index.ts", "src/assets/javascripts/browser/location/hash/index.ts", "src/assets/javascripts/browser/media/index.ts", "src/assets/javascripts/browser/request/index.ts", "src/assets/javascripts/browser/viewport/offset/index.ts", "src/assets/javascripts/browser/viewport/size/index.ts", "src/assets/javascripts/browser/viewport/_/index.ts", "src/assets/javascripts/browser/worker/index.ts", "src/assets/javascripts/_/index.ts", "src/assets/javascripts/components/_/index.ts", "src/assets/javascripts/components/content/code/index.ts", "src/assets/javascripts/actions/_/index.ts", "src/assets/javascripts/actions/anchor/index.ts", "src/assets/javascripts/actions/dialog/index.ts", "src/assets/javascripts/actions/header/_/index.ts", "src/assets/javascripts/actions/header/title/index.ts", "src/assets/javascripts/actions/search/query/index.ts", "src/assets/javascripts/utilities/h/index.ts", "src/assets/javascripts/utilities/string/index.ts", "src/assets/javascripts/actions/search/result/index.ts", "src/assets/javascripts/actions/sidebar/index.ts", "src/assets/javascripts/actions/source/index.ts", "src/assets/javascripts/actions/tabs/index.ts", "src/assets/javascripts/actions/top/index.ts", "src/assets/javascripts/templates/clipboard/index.tsx", "src/assets/javascripts/templates/search/index.tsx", "src/assets/javascripts/templates/source/index.tsx", "src/assets/javascripts/templates/table/index.tsx", "src/assets/javascripts/templates/version/index.tsx", "src/assets/javascripts/components/content/details/index.ts", "src/assets/javascripts/components/content/table/index.ts", "src/assets/javascripts/components/content/_/index.ts", "src/assets/javascripts/components/dialog/index.ts", "src/assets/javascripts/components/header/_/index.ts", "src/assets/javascripts/components/header/title/index.ts", "src/assets/javascripts/components/main/index.ts", "src/assets/javascripts/components/palette/index.ts", "src/assets/javascripts/integrations/clipboard/index.ts", "src/assets/javascripts/integrations/instant/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/transform/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts", "src/assets/javascripts/integrations/search/worker/_/index.ts", "src/assets/javascripts/integrations/version/index.ts", "src/assets/javascripts/components/search/query/index.ts", "src/assets/javascripts/components/search/result/index.ts", "src/assets/javascripts/components/search/share/index.ts", "src/assets/javascripts/components/search/suggest/index.ts", "src/assets/javascripts/components/search/_/index.ts", "src/assets/javascripts/components/search/highlight/index.ts", "src/assets/javascripts/components/sidebar/index.ts", "src/assets/javascripts/components/source/facts/github/index.ts", "src/assets/javascripts/components/source/facts/gitlab/index.ts", "src/assets/javascripts/components/source/facts/_/index.ts", "src/assets/javascripts/components/source/_/index.ts", "src/assets/javascripts/components/tabs/index.ts", "src/assets/javascripts/components/toc/index.ts", "src/assets/javascripts/components/top/index.ts", "src/assets/javascripts/patches/indeterminate/index.ts", "src/assets/javascripts/patches/scrollfix/index.ts", "src/assets/javascripts/patches/scrolllock/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global global, define, System, Reflect, Promise */\r\nvar __extends;\r\nvar __assign;\r\nvar __rest;\r\nvar __decorate;\r\nvar __param;\r\nvar __metadata;\r\nvar __awaiter;\r\nvar __generator;\r\nvar __exportStar;\r\nvar __values;\r\nvar __read;\r\nvar __spread;\r\nvar __spreadArrays;\r\nvar __spreadArray;\r\nvar __await;\r\nvar __asyncGenerator;\r\nvar __asyncDelegator;\r\nvar __asyncValues;\r\nvar __makeTemplateObject;\r\nvar __importStar;\r\nvar __importDefault;\r\nvar __classPrivateFieldGet;\r\nvar __classPrivateFieldSet;\r\nvar __createBinding;\r\n(function (factory) {\r\n var root = typeof global === \"object\" ? global : typeof self === \"object\" ? self : typeof this === \"object\" ? this : {};\r\n if (typeof define === \"function\" && define.amd) {\r\n define(\"tslib\", [\"exports\"], function (exports) { factory(createExporter(root, createExporter(exports))); });\r\n }\r\n else if (typeof module === \"object\" && typeof module.exports === \"object\") {\r\n factory(createExporter(root, createExporter(module.exports)));\r\n }\r\n else {\r\n factory(createExporter(root));\r\n }\r\n function createExporter(exports, previous) {\r\n if (exports !== root) {\r\n if (typeof Object.create === \"function\") {\r\n Object.defineProperty(exports, \"__esModule\", { value: true });\r\n }\r\n else {\r\n exports.__esModule = true;\r\n }\r\n }\r\n return function (id, v) { return exports[id] = previous ? previous(id, v) : v; };\r\n }\r\n})\r\n(function (exporter) {\r\n var extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n\r\n __extends = function (d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n };\r\n\r\n __assign = Object.assign || function (t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n };\r\n\r\n __rest = function (s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n };\r\n\r\n __decorate = function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n };\r\n\r\n __param = function (paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n };\r\n\r\n __metadata = function (metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n };\r\n\r\n __awaiter = function (thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n };\r\n\r\n __generator = function (thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n };\r\n\r\n __exportStar = function(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n };\r\n\r\n __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n }) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n });\r\n\r\n __values = function (o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n };\r\n\r\n __read = function (o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spread = function () {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spreadArrays = function () {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n };\r\n\r\n __spreadArray = function (to, from) {\r\n for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)\r\n to[j] = from[i];\r\n return to;\r\n };\r\n\r\n __await = function (v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n };\r\n\r\n __asyncGenerator = function (thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n };\r\n\r\n __asyncDelegator = function (o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n };\r\n\r\n __asyncValues = function (o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n };\r\n\r\n __makeTemplateObject = function (cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n };\r\n\r\n var __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n }) : function(o, v) {\r\n o[\"default\"] = v;\r\n };\r\n\r\n __importStar = function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n };\r\n\r\n __importDefault = function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n };\r\n\r\n __classPrivateFieldGet = function (receiver, privateMap) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to get private field on non-instance\");\r\n }\r\n return privateMap.get(receiver);\r\n };\r\n\r\n __classPrivateFieldSet = function (receiver, privateMap, value) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to set private field on non-instance\");\r\n }\r\n privateMap.set(receiver, value);\r\n return value;\r\n };\r\n\r\n exporter(\"__extends\", __extends);\r\n exporter(\"__assign\", __assign);\r\n exporter(\"__rest\", __rest);\r\n exporter(\"__decorate\", __decorate);\r\n exporter(\"__param\", __param);\r\n exporter(\"__metadata\", __metadata);\r\n exporter(\"__awaiter\", __awaiter);\r\n exporter(\"__generator\", __generator);\r\n exporter(\"__exportStar\", __exportStar);\r\n exporter(\"__createBinding\", __createBinding);\r\n exporter(\"__values\", __values);\r\n exporter(\"__read\", __read);\r\n exporter(\"__spread\", __spread);\r\n exporter(\"__spreadArrays\", __spreadArrays);\r\n exporter(\"__spreadArray\", __spreadArray);\r\n exporter(\"__await\", __await);\r\n exporter(\"__asyncGenerator\", __asyncGenerator);\r\n exporter(\"__asyncDelegator\", __asyncDelegator);\r\n exporter(\"__asyncValues\", __asyncValues);\r\n exporter(\"__makeTemplateObject\", __makeTemplateObject);\r\n exporter(\"__importStar\", __importStar);\r\n exporter(\"__importDefault\", __importDefault);\r\n exporter(\"__classPrivateFieldGet\", __classPrivateFieldGet);\r\n exporter(\"__classPrivateFieldSet\", __classPrivateFieldSet);\r\n});\r\n", "/*!\n * clipboard.js v2.0.8\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 134:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/clipboard-action.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n/**\n * Inner class which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n */\n\nvar ClipboardAction = /*#__PURE__*/function () {\n /**\n * @param {Object} options\n */\n function ClipboardAction(options) {\n _classCallCheck(this, ClipboardAction);\n\n this.resolveOptions(options);\n this.initSelection();\n }\n /**\n * Defines base properties passed from constructor.\n * @param {Object} options\n */\n\n\n _createClass(ClipboardAction, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = options.action;\n this.container = options.container;\n this.emitter = options.emitter;\n this.target = options.target;\n this.text = options.text;\n this.trigger = options.trigger;\n this.selectedText = '';\n }\n /**\n * Decides which selection strategy is going to be applied based\n * on the existence of `text` and `target` properties.\n */\n\n }, {\n key: \"initSelection\",\n value: function initSelection() {\n if (this.text) {\n this.selectFake();\n } else if (this.target) {\n this.selectTarget();\n }\n }\n /**\n * Creates a fake textarea element, sets its value from `text` property,\n */\n\n }, {\n key: \"createFakeElement\",\n value: function createFakeElement() {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS\n\n this.fakeElem.style.fontSize = '12pt'; // Reset box model\n\n this.fakeElem.style.border = '0';\n this.fakeElem.style.padding = '0';\n this.fakeElem.style.margin = '0'; // Move element out of screen horizontally\n\n this.fakeElem.style.position = 'absolute';\n this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n this.fakeElem.style.top = \"\".concat(yPosition, \"px\");\n this.fakeElem.setAttribute('readonly', '');\n this.fakeElem.value = this.text;\n return this.fakeElem;\n }\n /**\n * Get's the value of fakeElem,\n * and makes a selection on it.\n */\n\n }, {\n key: \"selectFake\",\n value: function selectFake() {\n var _this = this;\n\n var fakeElem = this.createFakeElement();\n\n this.fakeHandlerCallback = function () {\n return _this.removeFake();\n };\n\n this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;\n this.container.appendChild(fakeElem);\n this.selectedText = select_default()(fakeElem);\n this.copyText();\n this.removeFake();\n }\n /**\n * Only removes the fake element after another click event, that way\n * a user can hit `Ctrl+C` to copy because selection still exists.\n */\n\n }, {\n key: \"removeFake\",\n value: function removeFake() {\n if (this.fakeHandler) {\n this.container.removeEventListener('click', this.fakeHandlerCallback);\n this.fakeHandler = null;\n this.fakeHandlerCallback = null;\n }\n\n if (this.fakeElem) {\n this.container.removeChild(this.fakeElem);\n this.fakeElem = null;\n }\n }\n /**\n * Selects the content from element passed on `target` property.\n */\n\n }, {\n key: \"selectTarget\",\n value: function selectTarget() {\n this.selectedText = select_default()(this.target);\n this.copyText();\n }\n /**\n * Executes the copy operation based on the current selection.\n */\n\n }, {\n key: \"copyText\",\n value: function copyText() {\n var succeeded;\n\n try {\n succeeded = document.execCommand(this.action);\n } catch (err) {\n succeeded = false;\n }\n\n this.handleResult(succeeded);\n }\n /**\n * Fires an event based on the copy operation result.\n * @param {Boolean} succeeded\n */\n\n }, {\n key: \"handleResult\",\n value: function handleResult(succeeded) {\n this.emitter.emit(succeeded ? 'success' : 'error', {\n action: this.action,\n text: this.selectedText,\n trigger: this.trigger,\n clearSelection: this.clearSelection.bind(this)\n });\n }\n /**\n * Moves focus away from `target` and back to the trigger, removes current selection.\n */\n\n }, {\n key: \"clearSelection\",\n value: function clearSelection() {\n if (this.trigger) {\n this.trigger.focus();\n }\n\n document.activeElement.blur();\n window.getSelection().removeAllRanges();\n }\n /**\n * Sets the `action` to be performed which can be either 'copy' or 'cut'.\n * @param {String} action\n */\n\n }, {\n key: \"destroy\",\n\n /**\n * Destroy lifecycle.\n */\n value: function destroy() {\n this.removeFake();\n }\n }, {\n key: \"action\",\n set: function set() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';\n this._action = action;\n\n if (this._action !== 'copy' && this._action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n }\n }\n /**\n * Gets the `action` property.\n * @return {String}\n */\n ,\n get: function get() {\n return this._action;\n }\n /**\n * Sets the `target` property using an element\n * that will be have its content copied.\n * @param {Element} target\n */\n\n }, {\n key: \"target\",\n set: function set(target) {\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (this.action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n\n this._target = target;\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n }\n }\n /**\n * Gets the `target` property.\n * @return {String|HTMLElement}\n */\n ,\n get: function get() {\n return this._target;\n }\n }]);\n\n return ClipboardAction;\n}();\n\n/* harmony default export */ var clipboard_action = (ClipboardAction);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction clipboard_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) clipboard_defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n clipboard_classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n clipboard_createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n\n if (this.clipboardAction) {\n this.clipboardAction = null;\n }\n\n this.clipboardAction = new clipboard_action({\n action: this.action(trigger),\n target: this.target(trigger),\n text: this.text(trigger),\n container: this.container,\n trigger: trigger,\n emitter: this\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n\n if (this.clipboardAction) {\n this.clipboardAction.destroy();\n this.clipboardAction = null;\n }\n }\n }], [{\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(134);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\nimport { NEVER, Subject, defer, merge } from \"rxjs\"\nimport {\n delay,\n filter,\n map,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getElement,\n requestJSON,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountBackToTop,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantLoading,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget()\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? __search?.index || requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up instant loading, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantLoading({ document$, location$, viewport$ })\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector()\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getElement(\"[href][rel=prev]\")\n if (typeof prev !== \"undefined\")\n prev.click()\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getElement(\"[href][rel=next]\")\n if (typeof next !== \"undefined\")\n next.click()\n break\n }\n })\n\n/* Set up patches */\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { target$, viewport$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : NEVER\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, { viewport$, header$ })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Tablet observable */\nwindow.screen$ = screen$ /* Screen observable */\nwindow.print$ = print$ /* Print mode observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.component$ = component$ /* Component observable */\n", "import tslib from '../tslib.js';\r\nconst {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n} = tslib;\r\nexport {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n};\r\n", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ReplaySubject, Subject, fromEvent } from \"rxjs\"\nimport { mapTo } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch document\n *\n * Documents are implemented as subjects, so all downstream observables are\n * automatically updated when a new document is emitted.\n *\n * @returns Document subject\n */\nexport function watchDocument(): Subject {\n const document$ = new ReplaySubject()\n fromEvent(document, \"DOMContentLoaded\")\n .pipe(\n mapTo(document)\n )\n .subscribe(document$)\n\n /* Return document */\n return document$\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T | undefined\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElementOrThrow(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElementOrThrow(\n selector: string, node?: ParentNode\n): T\n\nexport function getElementOrThrow(\n selector: string, node: ParentNode = document\n): T {\n const el = getElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n return el\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement\n : undefined\n}\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Create an element\n *\n * @template T - Tag name type\n *\n * @param tagName - Tag name\n *\n * @returns Element\n */\nexport function createElement(\n tagName: T\n): HTMLElementTagNameMap[T] {\n return document.createElement(tagName)\n}\n\n/**\n * Replace an element with the given list of nodes\n *\n * @param el - Element\n * @param nodes - Replacement nodes\n */\nexport function replaceElement(\n el: HTMLElement, ...nodes: Node[]\n): void {\n el.replaceWith(...nodes)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element focus\n *\n * @param el - Element\n * @param value - Whether the element should be focused\n */\nexport function setElementFocus(\n el: HTMLElement, value = true\n): void {\n if (value)\n el.focus()\n else\n el.blur()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"focus\"),\n fromEvent(el, \"blur\")\n )\n .pipe(\n map(({ type }) => type === \"focus\"),\n startWith(el === getActiveElement())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n of\n} from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(resize => NEVER.pipe(startWith(resize))\n .pipe(\n finalize(() => resize.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(el: HTMLElement): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/**\n * Retrieve element content size, i.e. including overflowing content\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementContentSize(el: HTMLElement): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that subscribes to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * Sadly, we can't use the `DOMRect` objects returned by the observer, because\n * we need the emitted values to be consistent with `getElementSize`, which will\n * return the used values (rounded) and not actual values (unrounded). Thus, we\n * use the `offset*` properties. See the linked GitHub issue.\n *\n * @see https://bit.ly/3m0k3he - GitHub issue\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(() => getElementSize(el))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n startWith\n} from \"rxjs/operators\"\n\nimport {\n getElementContentSize,\n getElementSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element offset\n *\n * @param el - Element\n *\n * @returns Element offset\n */\nexport function getElementOffset(el: HTMLElement): ElementOffset {\n return {\n x: el.scrollLeft,\n y: el.scrollTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element offset\n *\n * @param el - Element\n *\n * @returns Element offset observable\n */\nexport function watchElementOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"scroll\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n map(() => getElementOffset(el)),\n startWith(getElementOffset(el))\n )\n}\n\n/**\n * Watch element threshold\n *\n * This function returns an observable which emits whether the bottom scroll\n * offset of an elements is within a certain threshold.\n *\n * @param el - Element\n * @param threshold - Threshold\n *\n * @returns Element threshold observable\n */\nexport function watchElementThreshold(\n el: HTMLElement, threshold = 16\n): Observable {\n return watchElementOffset(el)\n .pipe(\n map(({ y }) => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return y >= (\n content.height - visible.height - threshold\n )\n }),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element text selection\n *\n * @param el - Element\n */\nexport function setElementSelection(\n el: HTMLElement\n): void {\n if (el instanceof HTMLInputElement)\n el.select()\n else\n throw new Error(\"Not implemented\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getElementOrThrow } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElementOrThrow(\"[data-md-toggle=drawer]\"),\n search: getElementOrThrow(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { filter, map, share } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../element\"\nimport { getToggle } from \"../toggle\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Keyboard mode\n */\nexport type KeyboardMode =\n | \"global\" /* Global */\n | \"search\" /* Search is open */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Keyboard\n */\nexport interface Keyboard {\n mode: KeyboardMode /* Keyboard mode */\n type: string /* Key type */\n claim(): void /* Key claim */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether an element may receive keyboard input\n *\n * @param el - Element\n *\n * @returns Test result\n */\nfunction isSusceptibleToKeyboard(el: HTMLElement): boolean {\n switch (el.tagName) {\n\n /* Form elements */\n case \"INPUT\":\n case \"SELECT\":\n case \"TEXTAREA\":\n return true\n\n /* Everything else */\n default:\n return el.isContentEditable\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch keyboard\n *\n * @returns Keyboard observable\n */\nexport function watchKeyboard(): Observable {\n return fromEvent(window, \"keydown\")\n .pipe(\n filter(ev => !(ev.metaKey || ev.ctrlKey)),\n map(ev => ({\n mode: getToggle(\"search\") ? \"search\" : \"global\",\n type: ev.key,\n claim() {\n ev.preventDefault()\n ev.stopPropagation()\n }\n } as Keyboard)),\n filter(({ mode }) => {\n if (mode === \"global\") {\n const active = getActiveElement()\n if (typeof active !== \"undefined\")\n return !isSusceptibleToKeyboard(active)\n }\n return true\n }),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function returns a `URL` object (and not `Location`) to normalize the\n * typings across the application. Furthermore, locations need to be tracked\n * without setting them and `Location` is a singleton which represents the\n * current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new Subject()\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport { filter, map, share, startWith, switchMap } from \"rxjs/operators\"\n\nimport { createElement, getElement } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = createElement(\"a\")\n el.href = hash\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n share()\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n switchMap(id => of(getElement(`[id=\"${id}\"]`)!))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n fromEvent,\n fromEventPattern\n} from \"rxjs\"\nimport {\n mapTo,\n startWith,\n switchMap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * Note that although `MediaQueryList.addListener` is deprecated we have to\n * use it, because it's the only way to ensure proper downward compatibility.\n *\n * @see https://bit.ly/3dUBH2m - GitHub issue\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEventPattern(next => (\n media.addListener(() => next(media.matches))\n ))\n .pipe(\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode, cross-browser\n *\n * @returns Print mode observable\n */\nexport function watchPrint(): Observable {\n return fromEvent(window, \"beforeprint\")\n .pipe(\n mapTo(undefined)\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Toggle an observable with a media observable\n *\n * @template T - Data type\n *\n * @param query$ - Media observable\n * @param factory - Observable factory\n *\n * @returns Toggled observable\n */\nexport function at(\n query$: Observable, factory: () => Observable\n): Observable {\n return query$\n .pipe(\n switchMap(active => active ? factory() : NEVER)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, from } from \"rxjs\"\nimport {\n filter,\n map,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the given URL\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Response observable\n */\nexport function request(\n url: URL | string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(`${url}`, options))\n .pipe(\n filter(res => res.status === 200),\n )\n}\n\n/**\n * Fetch JSON from the given URL\n *\n * @template T - Data type\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestJSON(\n url: URL | string, options?: RequestInit\n): Observable {\n return request(url, options)\n .pipe(\n switchMap(res => res.json()),\n shareReplay(1)\n )\n}\n\n/**\n * Fetch XML from the given URL\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestXML(\n url: URL | string, options?: RequestInit\n): Observable {\n const dom = new DOMParser()\n return request(url, options)\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/xml\")),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, pageXOffset),\n y: Math.max(0, pageYOffset)\n }\n}\n\n/**\n * Set viewport offset\n *\n * @param offset - Viewport offset\n */\nexport function setViewportOffset(\n { x, y }: Partial\n): void {\n window.scrollTo(x || 0, y || 0)\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, combineLatest } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n map,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { Header } from \"~/components\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch at options\n */\ninterface WatchAtOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
/* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchAtOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map((): ViewportOffset => ({\n x: el.offsetLeft,\n y: el.offsetTop\n }))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, fromEvent } from \"rxjs\"\nimport {\n map,\n share,\n switchMapTo,\n tap,\n throttle\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that sends all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data as T)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMapTo(rx$),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Flag =\n | \"header.autohide\" /* Hide header */\n | \"navigation.expand\" /* Automatic expansion */\n | \"navigation.instant\" /* Instant loading */\n | \"navigation.sections\" /* Sections navigation */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.top\" /* Back-to-top button */\n | \"search.highlight\" /* Search highlighting */\n | \"search.share\" /* Search sharing */\n | \"search.suggest\" /* Search suggestions */\n | \"toc.integrate\" /* Integrated table of contents */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n | \"select.version.title\" /* Version selector */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Versioning\n */\nexport interface Versioning {\n provider: \"mike\" /* Version provider */\n}\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Flag[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n version?: Versioning /* Versioning */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst script = getElementOrThrow(\"#__config\")\nconst config: Config = JSON.parse(script.textContent!)\nconfig.base = `${new URL(config.base, getLocation())}`\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature flag is enabled\n *\n * @param flag - Feature flag\n *\n * @returns Test result\n */\nexport function feature(flag: Flag): boolean {\n return config.features.includes(flag)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Positional value, if any\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component\n */\nexport type ComponentType =\n | \"announce\" /* Announcement bar */\n | \"container\" /* Container */\n | \"content\" /* Content */\n | \"dialog\" /* Dialog */\n | \"header\" /* Header */\n | \"header-title\" /* Header title */\n | \"header-topic\" /* Header topic */\n | \"main\" /* Main area */\n | \"palette\" /* Color palette */\n | \"search\" /* Search */\n | \"search-query\" /* Search input */\n | \"search-result\" /* Search results */\n | \"search-share\" /* Search sharing */\n | \"search-suggest\" /* Search suggestions */\n | \"sidebar\" /* Sidebar */\n | \"skip\" /* Skip link */\n | \"source\" /* Repository information */\n | \"tabs\" /* Navigation tabs */\n | \"toc\" /* Table of contents */\n | \"top\" /* Back-to-top button */\n\n/**\n * A component\n *\n * @template T - Component type\n * @template U - Reference type\n */\nexport type Component<\n T extends {} = {},\n U extends HTMLElement = HTMLElement\n> =\n T & {\n ref: U /* Component reference */\n }\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type map\n */\ninterface ComponentTypeMap {\n \"announce\": HTMLElement /* Announcement bar */\n \"container\": HTMLElement /* Container */\n \"content\": HTMLElement /* Content */\n \"dialog\": HTMLElement /* Dialog */\n \"header\": HTMLElement /* Header */\n \"header-title\": HTMLElement /* Header title */\n \"header-topic\": HTMLElement /* Header topic */\n \"main\": HTMLElement /* Main area */\n \"palette\": HTMLElement /* Color palette */\n \"search\": HTMLElement /* Search */\n \"search-query\": HTMLInputElement /* Search input */\n \"search-result\": HTMLElement /* Search results */\n \"search-share\": HTMLAnchorElement /* Search sharing */\n \"search-suggest\": HTMLElement /* Search suggestions */\n \"sidebar\": HTMLElement /* Sidebar */\n \"skip\": HTMLAnchorElement /* Skip link */\n \"source\": HTMLAnchorElement /* Repository information */\n \"tabs\": HTMLElement /* Navigation tabs */\n \"toc\": HTMLElement /* Table of contents */\n \"top\": HTMLAnchorElement /* Back-to-top button */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the element for a given component or throw a reference error\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getComponentElement(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T] {\n return getElementOrThrow(`[data-md-component=${type}]`, node)\n}\n\n/**\n * Retrieve all elements for a given component\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getComponentElements(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T][] {\n return getElements(`[data-md-component=${type}]`, node)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n NEVER,\n Observable,\n Subject,\n fromEvent,\n merge,\n of\n} from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n switchMap,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetFocusable, setFocusable } from \"~/actions\"\nimport {\n Viewport,\n getElementContentSize,\n getElementSize,\n getElements,\n watchMedia\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scroll: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global index for Clipboard.js integration\n */\nlet index = 0\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * This function monitors size changes of the viewport, as well as switches of\n * content tabs with embedded code blocks, as both may trigger overflow.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement, { viewport$ }: WatchOptions\n): Observable {\n const container$ = of(el)\n .pipe(\n switchMap(child => {\n const container = child.closest(\"[data-tabs]\")\n if (container instanceof HTMLElement) {\n return merge(\n ...getElements(\"input\", container)\n .map(input => fromEvent(input, \"change\"))\n )\n }\n return NEVER\n })\n )\n\n /* Check overflow on resize and tab change */\n return merge(\n viewport$.pipe(distinctUntilKeyChanged(\"size\")),\n container$\n )\n .pipe(\n map(() => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return {\n scroll: content.width > visible.width\n }\n }),\n distinctUntilKeyChanged(\"scroll\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that an overflowing code block is focusable through\n * keyboard, so it can be scrolled without a mouse to improve on accessibility.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n withLatestFrom(watchMedia(\"(hover)\"))\n )\n .subscribe(([{ scroll }, hover]) => {\n if (scroll && hover)\n setFocusable(el)\n else\n resetFocusable(el)\n })\n\n /* Render button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${index++}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Create and return component */\n return watchCodeBlock(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set focusable property\n *\n * @param el - Element\n * @param value - Tabindex value\n */\nexport function setFocusable(\n el: HTMLElement, value = 0\n): void {\n el.setAttribute(\"tabindex\", value.toString())\n}\n\n/**\n * Reset focusable property\n *\n * @param el - Element\n */\nexport function resetFocusable(\n el: HTMLElement\n): void {\n el.removeAttribute(\"tabindex\")\n}\n\n/**\n * Set scroll lock\n *\n * @param el - Scrollable element\n * @param value - Vertical offset\n */\nexport function setScrollLock(\n el: HTMLElement, value: number\n): void {\n el.setAttribute(\"data-md-state\", \"lock\")\n el.style.top = `-${value}px`\n}\n\n/**\n * Reset scroll lock\n *\n * @param el - Scrollable element\n */\nexport function resetScrollLock(\n el: HTMLElement\n): void {\n const value = -1 * parseInt(el.style.top, 10)\n el.removeAttribute(\"data-md-state\")\n el.style.top = \"\"\n if (value)\n window.scrollTo(0, value)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set anchor state\n *\n * @param el - Anchor element\n * @param state - Anchor state\n */\nexport function setAnchorState(\n el: HTMLElement, state: \"blur\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset anchor state\n *\n * @param el - Anchor element\n */\nexport function resetAnchorState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set anchor active\n *\n * @param el - Anchor element\n * @param value - Whether the anchor is active\n */\nexport function setAnchorActive(\n el: HTMLElement, value: boolean\n): void {\n el.classList.toggle(\"md-nav__link--active\", value)\n}\n\n/**\n * Reset anchor active\n *\n * @param el - Anchor element\n */\nexport function resetAnchorActive(\n el: HTMLElement\n): void {\n el.classList.remove(\"md-nav__link--active\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set dialog message\n *\n * @param el - Dialog element\n * @param value - Dialog message\n */\nexport function setDialogMessage(\n el: HTMLElement, value: string\n): void {\n el.firstElementChild!.innerHTML = value\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set dialog state\n *\n * @param el - Dialog element\n * @param state - Dialog state\n */\nexport function setDialogState(\n el: HTMLElement, state: \"open\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset dialog state\n *\n * @param el - Dialog element\n */\nexport function resetDialogState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header state\n *\n * @param el - Header element\n * @param state - Header state\n */\nexport function setHeaderState(\n el: HTMLElement, state: \"shadow\" | \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header state\n *\n * @param el - Header element\n */\nexport function resetHeaderState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header title state\n *\n * @param el - Header title element\n * @param state - Header title state\n */\nexport function setHeaderTitleState(\n el: HTMLElement, state: \"active\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header title state\n *\n * @param el - Header title element\n */\nexport function resetHeaderTitleState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set search query placeholder\n *\n * @param el - Search query element\n * @param value - Placeholder\n */\nexport function setSearchQueryPlaceholder(\n el: HTMLInputElement, value: string\n): void {\n el.placeholder = value\n}\n\n/**\n * Reset search query placeholder\n *\n * @param el - Search query element\n */\nexport function resetSearchQueryPlaceholder(\n el: HTMLInputElement\n): void {\n el.placeholder = translation(\"search.placeholder\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: string, attributes: Attributes | null, ...children: Child[]\n): HTMLElement {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes))\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else if (attributes[attr])\n el.setAttribute(attr, \"\")\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n\n/**\n * Simple hash function\n *\n * @see https://bit.ly/2wsVjJ4 - Original source\n *\n * @param value - Value to be hashed\n *\n * @returns Hash as 32bit integer\n */\nexport function hash(value: string): number {\n let h = 0\n for (let i = 0, len = value.length; i < len; i++) {\n h = ((h << 5) - h) + value.charCodeAt(i)\n h |= 0 // Convert to 32bit integer\n }\n return h\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set number of search results\n *\n * @param el - Search result metadata element\n * @param value - Number of results\n */\nexport function setSearchResultMeta(\n el: HTMLElement, value: number\n): void {\n switch (value) {\n\n /* No results */\n case 0:\n el.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n el.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n el.textContent = translation(\"search.result.other\", round(value))\n }\n}\n\n/**\n * Reset number of search results\n *\n * @param el - Search result metadata element\n */\nexport function resetSearchResultMeta(\n el: HTMLElement\n): void {\n el.textContent = translation(\"search.result.placeholder\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Add an element to the search result list\n *\n * @param el - Search result list element\n * @param child - Search result element\n */\nexport function addToSearchResultList(\n el: HTMLElement, child: Element\n): void {\n el.appendChild(child)\n}\n\n/**\n * Reset search result list\n *\n * @param el - Search result list element\n */\nexport function resetSearchResultList(\n el: HTMLElement\n): void {\n el.innerHTML = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar offset\n *\n * @param el - Sidebar element\n * @param value - Sidebar offset\n */\nexport function setSidebarOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset sidebar offset\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar height\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child \u2013 the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param value - Sidebar height\n */\nexport function setSidebarHeight(\n el: HTMLElement, value: number\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = `${value - 2 * scrollwrap.offsetTop}px`\n}\n\n/**\n * Reset sidebar height\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarHeight(\n el: HTMLElement\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set repository facts\n *\n * @param el - Repository element\n * @param child - Repository facts element\n */\nexport function setSourceFacts(\n el: HTMLElement, child: Element\n): void {\n el.lastElementChild!.appendChild(child)\n}\n\n/**\n * Set repository state\n *\n * @param el - Repository element\n * @param state - Repository state\n */\nexport function setSourceState(\n el: HTMLElement, state: \"done\"\n): void {\n el.lastElementChild!.setAttribute(\"data-md-state\", state)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set tabs state\n *\n * @param el - Tabs element\n * @param state - Tabs state\n */\nexport function setTabsState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset tabs state\n *\n * @param el - Tabs element\n */\nexport function resetTabsState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set back-to-top state\n *\n * @param el - Back-to-top element\n * @param state - Back-to-top state\n */\nexport function setBackToTopState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset back-to-top state\n *\n * @param el - Back-to-top element\n */\nexport function resetBackToTopState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set back-to-top offset\n *\n * @param el - Back-to-top element\n * @param value - Back-to-top offset\n */\nexport function setBackToTopOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset back-to-top offset\n *\n * @param el - Back-to-top element\n */\nexport function resetBackToTopOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string): HTMLElement {\n return (\n code`}\n >\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { feature, translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResultItem\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param document - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n): HTMLElement {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .map(key => [{key}, \" \"])\n .flat()\n .slice(0, -1)\n\n /* Assemble query string for highlighting */\n const url = new URL(document.location)\n if (feature(\"search.highlight\"))\n url.searchParams.set(\"h\", Object.entries(document.terms)\n .filter(([, match]) => match)\n .reduce((highlight, [value]) => `${highlight} ${value}`.trim(), \"\")\n )\n\n /* Render article or section, depending on flags */\n return (\n \n \n {parent > 0 &&
}\n

{document.title}

\n {teaser > 0 && document.text.length > 0 &&\n

\n {truncate(document.text, 320)}\n

\n }\n {teaser > 0 && missing.length > 0 &&\n

\n {translation(\"search.result.term.missing\")}: {...missing}\n

\n }\n \n
\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n *\n * @returns Element\n */\nexport function renderSearchResultItem(\n result: SearchResultItem\n): HTMLElement {\n const threshold = result[0].score\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
\n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
\n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h, round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts): HTMLElement {\n return (\n
      \n {Object.entries(facts).map(([key, value]) => (\n
    • \n {typeof value === \"number\" ? round(value) : value}\n
    • \n ))}\n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement): HTMLElement {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration, translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Version\n */\nexport interface Version {\n version: string /* Version identifier */\n title: string /* Version title */\n aliases: string[] /* Version aliases */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version\n *\n * @param version - Version\n *\n * @returns Element\n */\nfunction renderVersion(version: Version): HTMLElement {\n const config = configuration()\n\n /* Ensure trailing slash, see https://bit.ly/3rL5u3f */\n const url = new URL(`../${version.version}/`, config.base)\n return (\n
  • \n \n {version.title}\n \n
  • \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version selector\n *\n * @param versions - Versions\n *\n * @returns Element\n */\nexport function renderVersionSelector(versions: Version[]): HTMLElement {\n const config = configuration()\n\n /* Determine active version */\n const [, current] = config.base.match(/([^/]+)\\/?$/)!\n const active =\n versions.find(({ version, aliases }) => (\n version === current || aliases.includes(current)\n )) || versions[0]\n\n /* Render version selector */\n return (\n
    \n \n {active.title}\n \n
      \n {versions.map(renderVersion)}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n mapTo,\n mergeWith,\n tap\n} from \"rxjs/operators\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print mode observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print mode observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n return target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n mergeWith(print$),\n mapTo(el)\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened on anchor jumps and\n * prior to printing, so the whole content of the page is visible.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$.subscribe(() => {\n el.setAttribute(\"open\", \"\")\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n mapTo({ ref: el })\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { createElement, replaceElement } from \"~/browser\"\nimport { renderTable } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = createElement(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * This function wraps a data table in another scrollable container, so it can\n * be smoothly scrolled on smaller screen sizes and won't break the layout.\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n replaceElement(el, sentinel)\n replaceElement(sentinel, renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { Viewport, getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { CodeBlock, mountCodeBlock } from \"../code\"\nimport { Details, mountDetails } from \"../details\"\nimport { DataTable, mountDataTable } from \"../table\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | CodeBlock\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n viewport$: Observable /* Viewport observable */\n print$: Observable /* Print mode observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * This function mounts all components that are found in the content of the\n * actual article, including code blocks, data tables and details.\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, viewport$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre > code\", el)\n .map(child => mountCodeBlock(child, { viewport$ })),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n delay,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetDialogState,\n setDialogMessage,\n setDialogState\n} from \"~/actions\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n open: boolean /* Dialog is visible */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n alert$: Subject /* Alert subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { alert$ }: WatchOptions\n): Observable {\n return alert$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(open => ({ message, open }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * This function reveals the dialog in the right cornerwhen a new alert is\n * emitted through the subject that is passed as part of the options.\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ message, open }) => {\n setDialogMessage(el, message)\n if (open)\n setDialogState(el, \"open\")\n else\n resetDialogState(el)\n })\n\n /* Create and return component */\n return watchDialog(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest,\n defer,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n combineLatestWith,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n observeOn,\n shareReplay,\n startWith,\n switchMap\n} from \"rxjs/operators\"\n\nimport { feature } from \"~/_\"\nimport { resetHeaderState, setHeaderState } from \"~/actions\"\nimport {\n Viewport,\n watchElementSize,\n watchToggle\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n height: number /* Header visible height */\n sticky: boolean /* Header stickyness */\n hidden: boolean /* User scrolled past threshold */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute whether the header is hidden\n *\n * If the user scrolls past a certain threshold, the header can be hidden when\n * scrolling down, and shown when scrolling up.\n *\n * @param options - Options\n *\n * @returns Toggle observable\n */\nfunction isHidden({ viewport$ }: WatchOptions): Observable {\n if (!feature(\"header.autohide\"))\n return of(false)\n\n /* Compute direction and turning point */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => [a < b, b] as const),\n distinctUntilKeyChanged(0)\n )\n\n /* Compute whether header should be hidden */\n const hidden$ = combineLatest([viewport$, direction$])\n .pipe(\n filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),\n map(([, [direction]]) => direction),\n distinctUntilChanged()\n )\n\n /* Compute threshold for hiding */\n const search$ = watchToggle(\"search\")\n return combineLatest([viewport$, search$])\n .pipe(\n map(([{ offset }, search]) => offset.y > 400 && !search),\n distinctUntilChanged(),\n switchMap(active => active ? hidden$ : of(false)),\n startWith(false)\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement, options: WatchOptions\n): Observable
    {\n return defer(() => {\n const styles = getComputedStyle(el)\n return of(\n styles.position === \"sticky\" ||\n styles.position === \"-webkit-sticky\"\n )\n })\n .pipe(\n combineLatestWith(watchElementSize(el), isHidden(options)),\n map(([sticky, { height }, hidden]) => ({\n height: sticky ? height : 0,\n sticky,\n hidden\n })),\n distinctUntilChanged((a, b) => (\n a.sticky === b.sticky &&\n a.height === b.height &&\n a.hidden === b.hidden\n )),\n shareReplay(1)\n )\n}\n\n/**\n * Mount header\n *\n * This function manages the different states of the header, i.e. whether it's\n * hidden or rendered with a shadow. This depends heavily on the main area.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n combineLatestWith(header$),\n observeOn(animationFrameScheduler)\n )\n .subscribe(([{ active }, { hidden }]) => {\n if (active)\n setHeaderState(el, hidden ? \"hidden\" : \"shadow\")\n else\n resetHeaderState(el)\n })\n\n /* Connect to long-living subject and return component */\n main$.subscribe(main => internal$.next(main))\n return header$\n .pipe(\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n animationFrameScheduler\n} from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetHeaderTitleState,\n setHeaderTitleState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* User scrolled past first headline */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLHeadingElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * This function swaps the header title from the site title to the title of the\n * current page when the user scrolls past the first headline.\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderTitleState(el, \"active\")\n else\n resetHeaderTitleState(el)\n })\n\n /* Obtain headline, if any */\n const headline = getElement(\"article h1\")\n if (typeof headline === \"undefined\")\n return NEVER\n\n /* Create and return component */\n return watchHeaderTitle(headline, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n switchMap\n} from \"rxjs/operators\"\n\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n ))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent,\n of\n} from \"rxjs\"\nimport {\n finalize,\n map,\n mapTo,\n mergeMap,\n shareReplay,\n startWith,\n tap\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Palette colors\n */\nexport interface PaletteColor {\n scheme?: string /* Color scheme */\n primary?: string /* Primary color */\n accent?: string /* Accent color */\n}\n\n/**\n * Palette\n */\nexport interface Palette {\n index: number /* Palette index */\n color: PaletteColor /* Palette colors */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch color palette\n *\n * @param inputs - Color palette element\n *\n * @returns Color palette observable\n */\nexport function watchPalette(\n inputs: HTMLInputElement[]\n): Observable {\n const data = localStorage.getItem(__prefix(\"__palette\"))!\n const current = JSON.parse(data) || {\n index: inputs.findIndex(input => (\n matchMedia(input.getAttribute(\"data-md-color-media\")!).matches\n ))\n }\n\n /* Emit changes in color palette */\n const palette$ = of(...inputs)\n .pipe(\n mergeMap(input => fromEvent(input, \"change\")\n .pipe(\n mapTo(input)\n )\n ),\n startWith(inputs[Math.max(0, current.index)]),\n map(input => ({\n index: inputs.indexOf(input),\n color: {\n scheme: input.getAttribute(\"data-md-color-scheme\"),\n primary: input.getAttribute(\"data-md-color-primary\"),\n accent: input.getAttribute(\"data-md-color-accent\")\n }\n } as Palette)),\n shareReplay(1)\n )\n\n /* Persist preference in local storage */\n palette$.subscribe(palette => {\n localStorage.setItem(__prefix(\"__palette\"), JSON.stringify(palette))\n })\n\n /* Return palette */\n return palette$\n}\n\n/**\n * Mount color palette\n *\n * @param el - Color palette element\n *\n * @returns Color palette component observable\n */\nexport function mountPalette(\n el: HTMLElement\n): Observable> {\n const internal$ = new Subject()\n\n /* Set color palette */\n internal$.subscribe(palette => {\n for (const [key, value] of Object.entries(palette.color))\n if (typeof value === \"string\")\n document.body.setAttribute(`data-md-color-${key}`, value)\n\n /* Toggle visibility */\n for (let index = 0; index < inputs.length; index++) {\n const label = inputs[index].nextElementSibling\n if (label instanceof HTMLElement)\n label.hidden = palette.index !== index\n }\n })\n\n /* Create and return component */\n const inputs = getElements(\"input\", el)\n return watchPalette(inputs)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { Observable, Subject } from \"rxjs\"\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @param options - Options\n */\nexport function setupClipboardJS(\n { alert$ }: SetupOptions\n): void {\n if (ClipboardJS.isSupported()) {\n new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\")\n .on(\"success\", ev => subscriber.next(ev))\n })\n .subscribe(() => alert$.next(translation(\"clipboard.copied\")))\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n fromEvent,\n merge,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n catchError,\n concatMap,\n debounceTime,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n sample,\n share,\n skip,\n skipUntil,\n switchMap\n} from \"rxjs/operators\"\n\nimport { configuration } from \"~/_\"\nimport {\n Viewport,\n ViewportOffset,\n createElement,\n getElement,\n getElements,\n replaceElement,\n request,\n requestXML,\n setLocation,\n setLocationHash,\n setViewportOffset\n} from \"~/browser\"\nimport { getComponentElement } from \"~/components\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * History state\n */\nexport interface HistoryState {\n url: URL /* State URL */\n offset?: ViewportOffset /* State viewport offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n document$: Subject /* Document subject */\n location$: Subject /* Location subject */\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Preprocess a list of URLs\n *\n * This function replaces the `site_url` in the sitemap with the actual base\n * URL, to allow instant loading to work in occasions like Netlify previews.\n *\n * @param urls - URLs\n *\n * @returns Processed URLs\n */\nfunction preprocess(urls: string[]): string[] {\n if (urls.length < 2)\n return urls\n\n /* Take the first two URLs and remove everything after the last slash */\n const [root, next] = urls\n .sort((a, b) => a.length - b.length)\n .map(url => url.replace(/[^/]+$/, \"\"))\n\n /* Compute common prefix */\n let index = 0\n if (root === next)\n index = root.length\n else\n while (root.charCodeAt(index) === next.charCodeAt(index))\n index++\n\n /* Replace common prefix (i.e. base) with effective base */\n const config = configuration()\n return urls.map(url => (\n url.replace(root.slice(0, index), config.base)\n ))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up instant loading\n *\n * When fetching, theoretically, we could use `responseType: \"document\"`, but\n * since all MkDocs links are relative, we need to make sure that the current\n * location matches the document we just loaded. Otherwise any relative links\n * in the document could use the old location.\n *\n * This is the reason why we need to synchronize history events and the process\n * of fetching the document for navigation changes (except `popstate` events):\n *\n * 1. Fetch document via `XMLHTTPRequest`\n * 2. Set new location via `history.pushState`\n * 3. Parse and emit fetched document\n *\n * For `popstate` events, we must not use `history.pushState`, or the forward\n * history will be irreversibly overwritten. In case the request fails, the\n * location change is dispatched regularly.\n *\n * @param options - Options\n */\nexport function setupInstantLoading(\n { document$, location$, viewport$ }: SetupOptions\n): void {\n const config = configuration()\n if (location.protocol === \"file:\")\n return\n\n /* Disable automatic scroll restoration */\n if (\"scrollRestoration\" in history) {\n history.scrollRestoration = \"manual\"\n\n /* Hack: ensure that reloads restore viewport offset */\n fromEvent(window, \"beforeunload\")\n .subscribe(() => {\n history.scrollRestoration = \"auto\"\n })\n }\n\n /* Hack: ensure absolute favicon link to omit 404s when switching */\n const favicon = getElement(\"link[rel=icon]\")\n if (typeof favicon !== \"undefined\")\n favicon.href = favicon.href\n\n /* Intercept internal navigation */\n const push$ = requestXML(new URL(\"sitemap.xml\", config.base))\n .pipe(\n map(sitemap => preprocess(getElements(\"loc\", sitemap)\n .map(node => node.textContent!)\n )),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n switchMap(ev => {\n\n /* Handle HTML and SVG elements */\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target) {\n const url = new URL(el.href)\n\n /* Canonicalize URL */\n url.search = \"\"\n url.hash = \"\"\n\n /* Check if URL should be intercepted */\n if (\n url.pathname !== location.pathname &&\n urls.includes(url.toString())\n ) {\n ev.preventDefault()\n return of({\n url: new URL(el.href)\n })\n }\n }\n }\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Intercept history back and forward */\n const pop$ = fromEvent(window, \"popstate\")\n .pipe(\n filter(ev => ev.state !== null),\n map(ev => ({\n url: new URL(location.href),\n offset: ev.state\n })),\n share()\n )\n\n /* Emit location change */\n merge(push$, pop$)\n .pipe(\n distinctUntilChanged((a, b) => a.url.href === b.url.href),\n map(({ url }) => url)\n )\n .subscribe(location$)\n\n /* Fetch document via `XMLHTTPRequest` */\n const response$ = location$\n .pipe(\n distinctUntilKeyChanged(\"pathname\"),\n switchMap(url => request(url.href)\n .pipe(\n catchError(() => {\n setLocation(url)\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Set new location via `history.pushState` */\n push$\n .pipe(\n sample(response$)\n )\n .subscribe(({ url }) => {\n history.pushState({}, \"\", `${url}`)\n })\n\n /* Parse and emit fetched document */\n const dom = new DOMParser()\n response$\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/html\"))\n )\n .subscribe(document$)\n\n /* Replace meta tags and components */\n document$\n .pipe(\n skip(1)\n )\n .subscribe(replacement => {\n for (const selector of [\n\n /* Meta tags */\n \"title\",\n \"link[rel=canonical]\",\n \"meta[name=author]\",\n \"meta[name=description]\",\n\n /* Components */\n \"[data-md-component=announce]\",\n \"[data-md-component=container]\",\n \"[data-md-component=header-topic]\",\n \"[data-md-component=logo], .md-logo\", // compat\n \"[data-md-component=skip]\"\n ]) {\n const source = getElement(selector)\n const target = getElement(selector, replacement)\n if (\n typeof source !== \"undefined\" &&\n typeof target !== \"undefined\"\n ) {\n replaceElement(source, target)\n }\n }\n })\n\n /* Re-evaluate scripts */\n document$\n .pipe(\n skip(1),\n map(() => getComponentElement(\"container\")),\n switchMap(el => of(...getElements(\"script\", el))),\n concatMap(el => {\n const script = createElement(\"script\")\n if (el.src) {\n for (const name of el.getAttributeNames())\n script.setAttribute(name, el.getAttribute(name)!)\n replaceElement(el, script)\n\n /* Complete when script is loaded */\n return new Observable(observer => {\n script.onload = () => observer.complete()\n })\n\n /* Complete immediately */\n } else {\n script.textContent = el.textContent\n replaceElement(el, script)\n return EMPTY\n }\n })\n )\n .subscribe()\n\n /* Emit history state change */\n merge(push$, pop$)\n .pipe(\n sample(document$),\n )\n .subscribe(({ url, offset }) => {\n if (url.hash && !offset) {\n setLocationHash(url.hash)\n } else {\n setViewportOffset(offset || { y: 0 })\n }\n })\n\n /* Debounce update of viewport offset */\n viewport$\n .pipe(\n skipUntil(push$),\n debounceTime(250),\n distinctUntilKeyChanged(\"offset\")\n )\n .subscribe(({ offset }) => {\n history.replaceState(offset, \"\")\n })\n\n /* Set viewport offset from history */\n merge(push$, pop$)\n .pipe(\n bufferCount(2, 1),\n filter(([a, b]) => a.url.pathname === b.url.pathname),\n map(([, state]) => state)\n )\n .subscribe(({ offset }) => {\n setViewportOffset(offset || { y: 0 })\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location and title */\n const location = doc.location\n const title = doc.title\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, Lunr.js doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * A message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * A message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * A message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ObservableInput, Subject, from } from \"rxjs\"\nimport { map, share } from \"rxjs/operators\"\n\nimport { configuration, feature, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex } from \"../../_\"\nimport {\n SearchOptions,\n SearchPipeline\n} from \"../../options\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex(\n { config, docs, index }: SearchIndex\n): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchPipeline\n\n /* Determine search options */\n const options: SearchOptions = {\n pipeline,\n suggestions: feature(\"search.suggest\")\n }\n\n /* Return search index after defaulting */\n return { config, docs, index, options }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search worker\n *\n * This function creates a web worker to set up and query the search index,\n * which is done using Lunr.js. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Search index observable input\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: ObservableInput\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data.items)\n for (const document of result)\n document.location = `${new URL(document.location, config.base)}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration } from \"~/_\"\nimport { getElementOrThrow, requestJSON } from \"~/browser\"\nimport { Version, renderVersionSelector } from \"~/templates\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up version selector\n */\nexport function setupVersionSelector(): void {\n const config = configuration()\n requestJSON(new URL(\"../versions.json\", config.base))\n .subscribe(versions => {\n const topic = getElementOrThrow(\".md-header__topic\")\n topic.appendChild(renderVersionSelector(versions))\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n fromEvent,\n merge\n} from \"rxjs\"\nimport {\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n finalize,\n map,\n take,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetSearchQueryPlaceholder,\n setSearchQueryPlaceholder\n} from \"~/actions\"\nimport {\n getLocation,\n setElementFocus,\n setToggle,\n watchElementFocus\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform,\n isSearchReadyMessage\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement, { rx$ }: SearchWorker\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1))\n )\n .pipe(\n map(() => fn(el.value)),\n distinctUntilChanged()\n )\n\n /* Intercept deep links */\n const location = getLocation()\n if (location.searchParams.has(\"q\")) {\n setToggle(\"search\", true)\n rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n .subscribe(() => {\n el.value = location.searchParams.get(\"q\")!\n setElementFocus(el)\n })\n }\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus }))\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$, rx$ }: SearchWorker\n): Observable> {\n const internal$ = new Subject()\n\n /* Handle value changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n setSearchQueryPlaceholder(el, \"\")\n } else {\n resetSearchQueryPlaceholder(el)\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(internal$.pipe(takeLast(1)))\n )\n .subscribe(() => setElementFocus(el))\n\n /* Create and return component */\n return watchSearchQuery(el, { tx$, rx$ })\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n filter,\n finalize,\n map,\n observeOn,\n switchMap,\n take,\n tap,\n withLatestFrom,\n zipWith\n} from \"rxjs/operators\"\n\nimport {\n addToSearchResultList,\n resetSearchResultList,\n resetSearchResultMeta,\n setSearchResultMeta\n} from \"~/actions\"\nimport {\n getElementOrThrow,\n watchElementThreshold\n} from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchReadyMessage,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResultItem } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * This function performs a lazy rendering of the search results, depending on\n * the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n const boundary$ = watchElementThreshold(el.parentElement!)\n .pipe(\n filter(Boolean)\n )\n\n /* Retrieve nested components */\n const meta = getElementOrThrow(\":scope > :first-child\", el)\n const list = getElementOrThrow(\":scope > :last-child\", el)\n\n /* Update search result metadata when ready */\n rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n .subscribe(() => {\n resetSearchResultMeta(meta)\n })\n\n /* Update search result metadata */\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(query$)\n )\n .subscribe(([{ items }, { value }]) => {\n if (value)\n setSearchResultMeta(meta, items.length)\n else\n resetSearchResultMeta(meta)\n })\n\n /* Update search result list */\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n tap(() => resetSearchResultList(list)),\n switchMap(({ items }) => merge(\n of(...items.slice(0, 10)),\n of(...items.slice(10))\n .pipe(\n bufferCount(4),\n zipWith(boundary$),\n switchMap(([chunk]) => of(...chunk))\n )\n ))\n )\n .subscribe(result => {\n addToSearchResultList(list, renderSearchResultItem(result))\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent\n} from \"rxjs\"\nimport {\n finalize,\n map,\n tap\n} from \"rxjs/operators\"\n\nimport { getLocation } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search sharing\n */\nexport interface SearchShare {\n url: URL /* Deep link for sharing */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n query$: Observable /* Search query observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search sharing\n *\n * @param _el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing observable\n */\nexport function watchSearchShare(\n _el: HTMLElement, { query$ }: WatchOptions\n): Observable {\n return query$\n .pipe(\n map(({ value }) => {\n const url = getLocation()\n url.hash = \"\"\n url.searchParams.delete(\"h\")\n url.searchParams.set(\"q\", value)\n return { url }\n })\n )\n}\n\n/**\n * Mount search sharing\n *\n * @param el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing component observable\n */\nexport function mountSearchShare(\n el: HTMLAnchorElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ url }) => {\n el.setAttribute(\"data-clipboard-text\", el.href)\n el.href = `${url}`\n })\n\n /* Prevent following of link */\n fromEvent(el, \"click\")\n .subscribe(ev => ev.preventDefault())\n\n /* Create and return component */\n return watchSearchShare(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n asyncScheduler,\n fromEvent\n} from \"rxjs\"\nimport {\n combineLatestWith,\n distinctUntilChanged,\n filter,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport { Keyboard } from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\n\nimport { Component, getComponentElement } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search suggestions\n */\nexport interface SearchSuggest {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search suggestions\n *\n * This function will perform a lazy rendering of the search results, depending\n * on the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchSuggest(\n el: HTMLElement, { rx$ }: SearchWorker, { keyboard$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n\n /* Retrieve query component and track all changes */\n const query = getComponentElement(\"search-query\")\n const query$ = fromEvent(query, \"keydown\")\n .pipe(\n observeOn(asyncScheduler),\n map(() => query.value),\n distinctUntilChanged(),\n )\n\n /* Update search suggestions */\n internal$\n .pipe(\n combineLatestWith(query$),\n map(([{ suggestions }, value]) => {\n const words = value.split(/([\\s-]+)/)\n if (suggestions?.length && words[words.length - 1]) {\n const last = suggestions[suggestions.length - 1]\n if (last.startsWith(words[words.length - 1]))\n words[words.length - 1] = last\n } else {\n words.length = 0\n }\n return words\n })\n )\n .subscribe(words => el.innerHTML = words\n .join(\"\")\n .replace(/\\s/g, \" \")\n )\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Right arrow: accept current suggestion */\n case \"ArrowRight\":\n if (\n el.innerText.length &&\n query.selectionStart === query.value.length\n )\n query.value = el.innerText\n break\n }\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(() => ({ ref: el }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, ObservableInput, merge } from \"rxjs\"\nimport { filter, mergeWith, sample, take } from \"rxjs/operators\"\n\nimport { configuration } from \"~/_\"\nimport {\n Keyboard,\n getActiveElement,\n getElements,\n setElementFocus,\n setElementSelection,\n setToggle\n} from \"~/browser\"\nimport {\n SearchIndex,\n SearchResult,\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport {\n Component,\n getComponentElement,\n getComponentElements\n} from \"../../_\"\nimport { SearchQuery, mountSearchQuery } from \"../query\"\nimport { mountSearchResult } from \"../result\"\nimport { SearchShare, mountSearchShare } from \"../share\"\nimport { SearchSuggest, mountSearchSuggest } from \"../suggest\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n | SearchShare\n | SearchSuggest\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * This function sets up the search functionality, including the underlying\n * web worker and all keyboard bindings.\n *\n * @param el - Search element\n * @param options - Options\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement, { index$, keyboard$ }: MountOptions\n): Observable> {\n const config = configuration()\n try {\n const url = __search?.worker || config.search\n const worker = setupSearchWorker(url, index$)\n\n /* Retrieve query and result components */\n const query = getComponentElement(\"search-query\", el)\n const result = getComponentElement(\"search-result\", el)\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n )\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n const active = getActiveElement()\n switch (key.type) {\n\n /* Enter: go to first (best) result */\n case \"Enter\":\n if (active === query) {\n const anchors = new Map()\n for (const anchor of getElements(\n \":first-child [href]\", result\n )) {\n const article = anchor.firstElementChild!\n anchors.set(anchor, parseFloat(\n article.getAttribute(\"data-md-score\")!\n ))\n }\n\n /* Go to result with highest score, if any */\n if (anchors.size) {\n const [[best]] = [...anchors].sort(([, a], [, b]) => b - a)\n best.click()\n }\n\n /* Otherwise omit form submission */\n key.claim()\n }\n break\n\n /* Escape or Tab: close search */\n case \"Escape\":\n case \"Tab\":\n setToggle(\"search\", false)\n setElementFocus(query, false)\n break\n\n /* Vertical arrows: select previous or next search result */\n case \"ArrowUp\":\n case \"ArrowDown\":\n if (typeof active === \"undefined\") {\n setElementFocus(query)\n } else {\n const els = [query, ...getElements(\n \":not(details) > [href], summary, details[open] [href]\",\n result\n )]\n const i = Math.max(0, (\n Math.max(0, els.indexOf(active)) + els.length + (\n key.type === \"ArrowUp\" ? -1 : +1\n )\n ) % els.length)\n setElementFocus(els[i])\n }\n\n /* Prevent scrolling of page */\n key.claim()\n break\n\n /* All other keys: hand to search query */\n default:\n if (query !== getActiveElement())\n setElementFocus(query)\n }\n })\n\n /* Set up global keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\"),\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Open search and select query */\n case \"f\":\n case \"s\":\n case \"/\":\n setElementFocus(query)\n setElementSelection(query)\n key.claim()\n break\n }\n })\n\n /* Create and return component */\n const query$ = mountSearchQuery(query, worker)\n const result$ = mountSearchResult(result, worker, { query$ })\n return merge(query$, result$)\n .pipe(\n mergeWith(\n\n /* Search sharing */\n ...getComponentElements(\"search-share\", el)\n .map(child => mountSearchShare(child, { query$ })),\n\n /* Search suggestions */\n ...getComponentElements(\"search-suggest\", el)\n .map(child => mountSearchSuggest(child, worker, { keyboard$ }))\n )\n )\n\n /* Gracefully handle broken search */\n } catch (err) {\n el.hidden = true\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n ObservableInput,\n combineLatest\n} from \"rxjs\"\nimport { filter, map, startWith } from \"rxjs/operators\"\n\nimport { getLocation } from \"~/browser\"\nimport {\n SearchIndex,\n setupSearchHighlighter\n} from \"~/integrations\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlighting\n */\nexport interface SearchHighlight {\n nodes: Map /* Map of replacements */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n location$: Observable /* Location observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search highlighting\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Search highlighting component observable\n */\nexport function mountSearchHiglight(\n el: HTMLElement, { index$, location$ }: MountOptions\n): Observable> {\n return combineLatest([\n index$,\n location$\n .pipe(\n startWith(getLocation()),\n filter(url => url.searchParams.has(\"h\"))\n )\n ])\n .pipe(\n map(([index, url]) => setupSearchHighlighter(index.config, true)(\n url.searchParams.get(\"h\")!\n )),\n map(fn => {\n const nodes = new Map()\n\n /* Traverse text nodes and collect matches */\n const it = document.createNodeIterator(el, NodeFilter.SHOW_TEXT)\n for (let node = it.nextNode(); node; node = it.nextNode()) {\n if (node.parentElement?.offsetHeight) {\n const original = node.textContent!\n const replaced = fn(original)\n if (replaced.length > original.length)\n nodes.set(node as ChildNode, replaced)\n }\n }\n\n /* Replace original nodes with matches */\n for (const [node, text] of nodes) {\n const { childNodes } = h(\"span\", null, text)\n node.replaceWith(...Array.from(childNodes))\n }\n\n /* Return component */\n return { ref: el, nodes }\n })\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetSidebarHeight,\n resetSidebarOffset,\n setSidebarHeight,\n setSidebarOffset\n} from \"~/actions\"\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const adjust =\n el.parentElement!.offsetTop -\n el.parentElement!.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Update height and offset */\n next([{ height }, { height: offset }]) {\n setSidebarHeight(el, height)\n setSidebarOffset(el, offset)\n },\n\n /* Reset on complete */\n complete() {\n resetSidebarOffset(el)\n resetSidebarHeight(el)\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport { Observable, zip } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * GitHub release (partial)\n */\ninterface Release {\n tag_name: string /* Tag name */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n if (typeof repo !== \"undefined\") {\n const url = `https://api.github.com/repos/${user}/${repo}`\n return zip(\n\n /* Fetch version */\n requestJSON(`${url}/releases/latest`)\n .pipe(\n map(release => ({\n version: release.tag_name\n })),\n defaultIfEmpty({})\n ),\n\n /* Fetch stars and forks */\n requestJSON(url)\n .pipe(\n map(info => ({\n stars: info.stargazers_count,\n forks: info.forks_count\n })),\n defaultIfEmpty({})\n )\n )\n .pipe(\n map(([release, info]) => ({ ...release, ...info }))\n )\n\n /* User or organization */\n } else {\n const url = `https://api.github.com/repos/${user}`\n return requestJSON(url)\n .pipe(\n map(info => ({\n repositories: info.public_repos\n })),\n defaultIfEmpty({})\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport { Observable } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return requestJSON(url)\n .pipe(\n map(({ star_count, forks_count }) => ({\n stars: star_count,\n forks: forks_count\n })),\n defaultIfEmpty({})\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts for repositories\n */\nexport interface RepositoryFacts {\n stars?: number /* Number of stars */\n forks?: number /* Number of forks */\n version?: string /* Latest version */\n}\n\n/**\n * Repository facts for organizations\n */\nexport interface OrganizationFacts {\n repositories?: number /* Number of repositories */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts =\n | RepositoryFacts\n | OrganizationFacts\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, defer, of } from \"rxjs\"\nimport {\n catchError,\n filter,\n finalize,\n map,\n shareReplay,\n tap\n} from \"rxjs/operators\"\n\nimport { setSourceFacts, setSourceState } from \"~/actions\"\nimport { renderSourceFacts } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SourceFacts, fetchSourceFacts } from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * This function tries to read the repository facts from session storage, and\n * if unsuccessful, fetches them from the underlying provider.\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n return fetch$ ||= defer(() => {\n const data = sessionStorage.getItem(__prefix(\"__source\"))\n if (data) {\n return of(JSON.parse(data))\n } else {\n const value$ = fetchSourceFacts(el.href)\n value$.subscribe(value => {\n try {\n sessionStorage.setItem(__prefix(\"__source\"), JSON.stringify(value))\n } catch (err) {\n /* Uncritical, just swallow */\n }\n })\n\n /* Return value */\n return value$\n }\n })\n .pipe(\n catchError(() => NEVER),\n filter(facts => Object.keys(facts).length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ facts }) => {\n setSourceFacts(el, renderSourceFacts(facts))\n setSourceState(el, \"done\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, animationFrameScheduler } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport { resetTabsState, setTabsState } from \"~/actions\"\nimport {\n Viewport,\n watchElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* User scrolled past tabs */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchElementSize(document.body)\n .pipe(\n switchMap(() => watchViewportAt(el, { header$, viewport$ })),\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * This function hides the navigation tabs when scrolling past the threshold\n * and makes them reappear in a nice CSS animation when scrolling back up.\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe({\n\n /* Update state */\n next({ hidden }) {\n if (hidden)\n setTabsState(el, \"hidden\")\n else\n resetTabsState(el)\n },\n\n /* Reset on complete */\n complete() {\n resetTabsState(el)\n }\n })\n\n /* Create and return component */\n return watchTabs(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n scan,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetAnchorActive,\n resetAnchorState,\n setAnchorActive,\n setAnchorState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElements,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param anchors - Anchor elements\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n anchors: HTMLAnchorElement[], { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(header => 24 + header.height)\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n map(() => {\n let path: HTMLAnchorElement[] = []\n return [...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map())\n }),\n\n /* Sort index by vertical offset (see https://bit.ly/30z6QSO) */\n map(index => new Map([...index].sort(([, a], [, b]) => a - b))),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(index => combineLatest([adjust$, viewport$])\n .pipe(\n scan(([prev, next], [adjust, { offset: { y } }]) => {\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Anchor list element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n resetAnchorActive(anchor)\n resetAnchorState(anchor)\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n setAnchorActive(anchor, index === prev.length - 1)\n setAnchorState(anchor, \"blur\")\n }\n })\n\n /* Create and return component */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n return watchTableOfContents(anchors, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetBackToTopOffset,\n resetBackToTopState,\n setBackToTopOffset,\n setBackToTopState\n} from \"~/actions\"\nimport { Viewport, setElementFocus } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Back-to-top button\n */\nexport interface BackToTop {\n hidden: boolean /* User scrolled up */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch back-to-top\n *\n * @param _el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top observable\n */\nexport function watchBackToTop(\n _el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n\n /* Compute direction */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => a > b && b),\n distinctUntilChanged()\n )\n\n /* Compute whether button should be hidden */\n const hidden$ = main$\n .pipe(\n distinctUntilKeyChanged(\"active\")\n )\n\n /* Compute threshold for hiding */\n return combineLatest([hidden$, direction$])\n .pipe(\n map(([{ active }, direction]) => ({\n hidden: !(active && direction)\n })),\n distinctUntilChanged((a, b) => (\n a.hidden === b.hidden\n ))\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount back-to-top\n *\n * @param el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top component observable\n */\nexport function mountBackToTop(\n el: HTMLElement, { viewport$, header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$\n .pipe(\n distinctUntilKeyChanged(\"height\")\n )\n )\n )\n .subscribe({\n\n /* Update state */\n next([{ hidden }, { height }]) {\n setBackToTopOffset(el, height + 16)\n if (hidden) {\n setBackToTopState(el, \"hidden\")\n setElementFocus(el, false)\n } else {\n resetBackToTopState(el)\n }\n },\n\n /* Reset on complete */\n complete() {\n resetBackToTopOffset(el)\n resetBackToTopState(el)\n }\n })\n\n /* Create and return component */\n return watchBackToTop(el, { viewport$, header$, main$ })\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport {\n mapTo,\n mergeMap,\n switchMap,\n takeWhile,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n tablet$: Observable /* Tablet breakpoint observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch indeterminate checkboxes\n *\n * This function replaces the indeterminate \"pseudo state\" with the actual\n * indeterminate state, which is used to keep navigation always expanded.\n *\n * @param options - Options\n */\nexport function patchIndeterminate(\n { document$, tablet$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\n \"[data-md-state=indeterminate]\"\n ))),\n tap(el => {\n el.indeterminate = true\n el.checked = false\n }),\n mergeMap(el => fromEvent(el, \"change\")\n .pipe(\n takeWhile(() => el.hasAttribute(\"data-md-state\")),\n mapTo(el)\n )\n ),\n withLatestFrom(tablet$)\n )\n .subscribe(([el, tablet]) => {\n el.removeAttribute(\"data-md-state\")\n if (tablet)\n el.checked = false\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport {\n filter,\n mapTo,\n mergeMap,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether the given device is an Apple device\n *\n * @returns Test result\n */\nfunction isAppleDevice(): boolean {\n return /(iPad|iPhone|iPod)/.test(navigator.userAgent)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch all elements with `data-md-scrollfix` attributes\n *\n * This is a year-old patch which ensures that overflow scrolling works at the\n * top and bottom of containers on iOS by ensuring a `1px` scroll offset upon\n * the start of a touch event.\n *\n * @see https://bit.ly/2SCtAOO - Original source\n *\n * @param options - Options\n */\nexport function patchScrollfix(\n { document$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\"[data-md-scrollfix]\"))),\n tap(el => el.removeAttribute(\"data-md-scrollfix\")),\n filter(isAppleDevice),\n mergeMap(el => fromEvent(el, \"touchstart\")\n .pipe(\n mapTo(el)\n )\n )\n )\n .subscribe(el => {\n const top = el.scrollTop\n\n /* We're at the top of the container */\n if (top === 0) {\n el.scrollTop = 1\n\n /* We're at the bottom of the container */\n } else if (top + el.offsetHeight === el.scrollHeight) {\n el.scrollTop = top - 1\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n combineLatest,\n of\n} from \"rxjs\"\nimport {\n delay,\n map,\n observeOn,\n switchMap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetScrollLock, setScrollLock } from \"~/actions\"\nimport { Viewport, watchToggle } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n viewport$: Observable /* Viewport observable */\n tablet$: Observable /* Tablet breakpoint observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch the document body to lock when search is open\n *\n * For mobile and tablet viewports, the search is rendered full screen, which\n * leads to scroll leaking when at the top or bottom of the search result. This\n * function locks the body when the search is in full screen mode, and restores\n * the scroll position when leaving.\n *\n * @param options - Options\n */\nexport function patchScrolllock(\n { viewport$, tablet$ }: PatchOptions\n): void {\n combineLatest([watchToggle(\"search\"), tablet$])\n .pipe(\n map(([active, tablet]) => active && !tablet),\n switchMap(active => of(active)\n .pipe(\n delay(active ? 400 : 100),\n observeOn(animationFrameScheduler)\n )\n ),\n withLatestFrom(viewport$)\n )\n .subscribe(([active, { offset: { y }}]) => {\n if (active)\n setScrollLock(document.body, y)\n else\n resetScrollLock(document.body)\n })\n}\n"], + "mappings": "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", + "names": [] +} diff --git a/assets/javascripts/lunr/min/lunr.ar.min.js b/assets/javascripts/lunr/min/lunr.ar.min.js new file mode 100644 index 0000000..248ddc5 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ar.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ar=function(){this.pipeline.reset(),this.pipeline.add(e.ar.trimmer,e.ar.stopWordFilter,e.ar.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ar.stemmer))},e.ar.wordCharacters="ء-ٛٱـ",e.ar.trimmer=e.trimmerSupport.generateTrimmer(e.ar.wordCharacters),e.Pipeline.registerFunction(e.ar.trimmer,"trimmer-ar"),e.ar.stemmer=function(){var e=this;return e.result=!1,e.preRemoved=!1,e.sufRemoved=!1,e.pre={pre1:"ف ك ب و س ل ن ا ي ت",pre2:"ال لل",pre3:"بال وال فال تال كال ولل",pre4:"فبال كبال وبال وكال"},e.suf={suf1:"ه ك ت ن ا ي",suf2:"نك نه ها وك يا اه ون ين تن تم نا وا ان كم كن ني نن ما هم هن تك ته ات يه",suf3:"تين كهم نيه نهم ونه وها يهم ونا ونك وني وهم تكم تنا تها تني تهم كما كها ناه نكم هنا تان يها",suf4:"كموه ناها ونني ونهم تكما تموه تكاه كماه ناكم ناهم نيها وننا"},e.patterns=JSON.parse('{"pt43":[{"pt":[{"c":"ا","l":1}]},{"pt":[{"c":"ا,ت,ن,ي","l":0}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"و","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ل","l":2,"m":3}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ي","l":2}],"mPt":[{"c":"ف","l":0,"m":0},{"c":"ع","l":1,"m":1},{"c":"ا","l":2},{"c":"ل","l":3,"m":3}]},{"pt":[{"c":"م","l":0}]}],"pt53":[{"pt":[{"c":"ت","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":3},{"c":"ل","l":3,"m":4},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":0},{"c":"ا","l":3}],"mPt":[{"c":"ف","l":0,"m":1},{"c":"ع","l":1,"m":2},{"c":"ل","l":2,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ن","l":4}]},{"pt":[{"c":"ت","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"م","l":0},{"c":"و","l":3}]},{"pt":[{"c":"ا","l":1},{"c":"و","l":3}]},{"pt":[{"c":"و","l":1},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ي","l":3}]},{"pt":[{"c":"ا","l":2},{"c":"ن","l":3}]},{"pt":[{"c":"م","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"م","l":0},{"c":"ا","l":2}]},{"pt":[{"c":"م","l":1},{"c":"ا","l":3}]},{"pt":[{"c":"ي,ت,ا,ن","l":0},{"c":"ت","l":1}],"mPt":[{"c":"ف","l":0,"m":2},{"c":"ع","l":1,"m":3},{"c":"ا","l":2},{"c":"ل","l":3,"m":4}]},{"pt":[{"c":"ت,ي,ا,ن","l":0},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ت","l":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":2},{"c":"ي","l":3}]},{"pt":[{"c":"ا,ي,ت,ن","l":0},{"c":"ن","l":1}],"mPt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ف","l":2,"m":2},{"c":"ع","l":3,"m":3},{"c":"ا","l":4},{"c":"ل","l":5,"m":4}]},{"pt":[{"c":"ا","l":3},{"c":"ء","l":4}]}],"pt63":[{"pt":[{"c":"ا","l":0},{"c":"ت","l":2},{"c":"ا","l":4}]},{"pt":[{"c":"ا,ت,ن,ي","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ا,ن,ت,ي","l":0},{"c":"و","l":3}]},{"pt":[{"c":"م","l":0},{"c":"س","l":1},{"c":"ت","l":2}],"mPt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ف","l":3,"m":3},{"c":"ع","l":4,"m":4},{"c":"ا","l":5},{"c":"ل","l":6,"m":5}]},{"pt":[{"c":"ي","l":1},{"c":"ي","l":3},{"c":"ا","l":4},{"c":"ء","l":5}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":1},{"c":"ا","l":4}]}],"pt54":[{"pt":[{"c":"ت","l":0}]},{"pt":[{"c":"ا,ي,ت,ن","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"م","l":0}],"mPt":[{"c":"ا","l":0},{"c":"ف","l":1,"m":1},{"c":"ع","l":2,"m":2},{"c":"ل","l":3,"m":3},{"c":"ر","l":4,"m":4},{"c":"ا","l":5},{"c":"ر","l":6,"m":4}]},{"pt":[{"c":"ا","l":2}]},{"pt":[{"c":"ا","l":0},{"c":"ن","l":2}]}],"pt64":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":4}]},{"pt":[{"c":"م","l":0},{"c":"ت","l":1}]}],"pt73":[{"pt":[{"c":"ا","l":0},{"c":"س","l":1},{"c":"ت","l":2},{"c":"ا","l":5}]}],"pt75":[{"pt":[{"c":"ا","l":0},{"c":"ا","l":5}]}]}'),e.execArray=["cleanWord","removeDiacritics","cleanAlef","removeStopWords","normalizeHamzaAndAlef","removeStartWaw","removePre432","removeEndTaa","wordCheck"],e.stem=function(){var r=0;for(e.result=!1,e.preRemoved=!1,e.sufRemoved=!1;r=0)return!0},e.normalizeHamzaAndAlef=function(){return e.word=e.word.replace("ؤ","ء"),e.word=e.word.replace("ئ","ء"),e.word=e.word.replace(/([\u0627])\1+/gi,"ا"),!1},e.removeEndTaa=function(){return!(e.word.length>2)||(e.word=e.word.replace(/[\u0627]$/,""),e.word=e.word.replace("ة",""),!1)},e.removeStartWaw=function(){return e.word.length>3&&"و"==e.word[0]&&"و"==e.word[1]&&(e.word=e.word.slice(1)),!1},e.removePre432=function(){var r=e.word;if(e.word.length>=7){var t=new RegExp("^("+e.pre.pre4.split(" ").join("|")+")");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=6){var c=new RegExp("^("+e.pre.pre3.split(" ").join("|")+")");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=5){var l=new RegExp("^("+e.pre.pre2.split(" ").join("|")+")");e.word=e.word.replace(l,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.patternCheck=function(r){for(var t=0;t3){var t=new RegExp("^("+e.pre.pre1.split(" ").join("|")+")");e.word=e.word.replace(t,"")}return r!=e.word&&(e.preRemoved=!0),!1},e.removeSuf1=function(){var r=e.word;if(0==e.sufRemoved&&e.word.length>3){var t=new RegExp("("+e.suf.suf1.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.removeSuf432=function(){var r=e.word;if(e.word.length>=6){var t=new RegExp("("+e.suf.suf4.split(" ").join("|")+")$");e.word=e.word.replace(t,"")}if(e.word==r&&e.word.length>=5){var c=new RegExp("("+e.suf.suf3.split(" ").join("|")+")$");e.word=e.word.replace(c,"")}if(e.word==r&&e.word.length>=4){var l=new RegExp("("+e.suf.suf2.split(" ").join("|")+")$");e.word=e.word.replace(l,"")}return r!=e.word&&(e.sufRemoved=!0),!1},e.wordCheck=function(){for(var r=(e.word,[e.removeSuf432,e.removeSuf1,e.removePre1]),t=0,c=!1;e.word.length>=7&&!e.result&&t=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.de.min.js b/assets/javascripts/lunr/min/lunr.de.min.js new file mode 100644 index 0000000..f3b5c10 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.de.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `German` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!v.eq_s(1,e)||(v.ket=v.cursor,!v.in_grouping(p,97,252)))&&(v.slice_from(r),v.cursor=n,!0)}function i(){for(var r,n,i,s,t=v.cursor;;)if(r=v.cursor,v.bra=r,v.eq_s(1,"ß"))v.ket=v.cursor,v.slice_from("ss");else{if(r>=v.limit)break;v.cursor=r+1}for(v.cursor=t;;)for(n=v.cursor;;){if(i=v.cursor,v.in_grouping(p,97,252)){if(s=v.cursor,v.bra=s,e("u","U",i))break;if(v.cursor=s,e("y","Y",i))break}if(i>=v.limit)return void(v.cursor=n);v.cursor=i+1}}function s(){for(;!v.in_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}for(;!v.out_grouping(p,97,252);){if(v.cursor>=v.limit)return!0;v.cursor++}return!1}function t(){m=v.limit,l=m;var e=v.cursor+3;0<=e&&e<=v.limit&&(d=e,s()||(m=v.cursor,m=v.limit)return;v.cursor++}}}function c(){return m<=v.cursor}function u(){return l<=v.cursor}function a(){var e,r,n,i,s=v.limit-v.cursor;if(v.ket=v.cursor,(e=v.find_among_b(w,7))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:v.slice_del(),v.ket=v.cursor,v.eq_s_b(1,"s")&&(v.bra=v.cursor,v.eq_s_b(3,"nis")&&v.slice_del());break;case 3:v.in_grouping_b(g,98,116)&&v.slice_del()}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(f,4))&&(v.bra=v.cursor,c()))switch(e){case 1:v.slice_del();break;case 2:if(v.in_grouping_b(k,98,116)){var t=v.cursor-3;v.limit_backward<=t&&t<=v.limit&&(v.cursor=t,v.slice_del())}}if(v.cursor=v.limit-s,v.ket=v.cursor,(e=v.find_among_b(_,8))&&(v.bra=v.cursor,u()))switch(e){case 1:v.slice_del(),v.ket=v.cursor,v.eq_s_b(2,"ig")&&(v.bra=v.cursor,r=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-r,u()&&v.slice_del()));break;case 2:n=v.limit-v.cursor,v.eq_s_b(1,"e")||(v.cursor=v.limit-n,v.slice_del());break;case 3:if(v.slice_del(),v.ket=v.cursor,i=v.limit-v.cursor,!v.eq_s_b(2,"er")&&(v.cursor=v.limit-i,!v.eq_s_b(2,"en")))break;v.bra=v.cursor,c()&&v.slice_del();break;case 4:v.slice_del(),v.ket=v.cursor,e=v.find_among_b(b,2),e&&(v.bra=v.cursor,u()&&1==e&&v.slice_del())}}var d,l,m,h=[new r("",-1,6),new r("U",0,2),new r("Y",0,1),new r("ä",0,3),new r("ö",0,4),new r("ü",0,5)],w=[new r("e",-1,2),new r("em",-1,1),new r("en",-1,2),new r("ern",-1,1),new r("er",-1,1),new r("s",-1,3),new r("es",5,2)],f=[new r("en",-1,1),new r("er",-1,1),new r("st",-1,2),new r("est",2,1)],b=[new r("ig",-1,1),new r("lich",-1,1)],_=[new r("end",-1,1),new r("ig",-1,2),new r("ung",-1,1),new r("lich",-1,3),new r("isch",-1,2),new r("ik",-1,2),new r("heit",-1,3),new r("keit",-1,4)],p=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],g=[117,30,5],k=[117,30,4],v=new n;this.setCurrent=function(e){v.setCurrent(e)},this.getCurrent=function(){return v.getCurrent()},this.stem=function(){var e=v.cursor;return i(),v.cursor=e,t(),v.limit_backward=e,v.cursor=v.limit,a(),v.cursor=v.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.du.min.js b/assets/javascripts/lunr/min/lunr.du.min.js new file mode 100644 index 0000000..49a0f3f --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.du.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Dutch` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e,r,i,o=C.cursor;;){if(C.bra=C.cursor,e=C.find_among(b,11))switch(C.ket=C.cursor,e){case 1:C.slice_from("a");continue;case 2:C.slice_from("e");continue;case 3:C.slice_from("i");continue;case 4:C.slice_from("o");continue;case 5:C.slice_from("u");continue;case 6:if(C.cursor>=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(r=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=r);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=r;else if(n(r))break}else if(n(r))break}function n(e){return C.cursor=e,e>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,f=_,t()||(_=C.cursor,_<3&&(_=3),t()||(f=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var e;;)if(C.bra=C.cursor,e=C.find_among(p,3))switch(C.ket=C.cursor,e){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return f<=C.cursor}function a(){var e=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-e,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var e;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.slice_del(),w=!0,a())))}function m(){var e;u()&&(e=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-e,C.eq_s_b(3,"gem")||(C.cursor=C.limit-e,C.slice_del(),a())))}function d(){var e,r,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,e=C.find_among_b(h,5))switch(C.bra=C.cursor,e){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(z,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(r=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-r,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,e=C.find_among_b(k,6))switch(C.bra=C.cursor,e){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(j,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var f,_,w,b=[new r("",-1,6),new r("á",0,1),new r("ä",0,1),new r("é",0,2),new r("ë",0,2),new r("í",0,3),new r("ï",0,3),new r("ó",0,4),new r("ö",0,4),new r("ú",0,5),new r("ü",0,5)],p=[new r("",-1,3),new r("I",0,2),new r("Y",0,1)],g=[new r("dd",-1,-1),new r("kk",-1,-1),new r("tt",-1,-1)],h=[new r("ene",-1,2),new r("se",-1,3),new r("en",-1,2),new r("heden",2,1),new r("s",-1,3)],k=[new r("end",-1,1),new r("ig",-1,2),new r("ing",-1,1),new r("lijk",-1,3),new r("baar",-1,4),new r("bar",-1,5)],v=[new r("aa",-1,-1),new r("ee",-1,-1),new r("oo",-1,-1),new r("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(e){C.setCurrent(e)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var r=C.cursor;return e(),C.cursor=r,o(),C.limit_backward=r,C.cursor=C.limit,d(),C.cursor=C.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.es.min.js b/assets/javascripts/lunr/min/lunr.es.min.js new file mode 100644 index 0000000..2989d34 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.es.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Spanish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,s){"function"==typeof define&&define.amd?define(s):"object"==typeof exports?module.exports=s():s()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.es=function(){this.pipeline.reset(),this.pipeline.add(e.es.trimmer,e.es.stopWordFilter,e.es.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.es.stemmer))},e.es.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.es.trimmer=e.trimmerSupport.generateTrimmer(e.es.wordCharacters),e.Pipeline.registerFunction(e.es.trimmer,"trimmer-es"),e.es.stemmer=function(){var s=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(){if(A.out_grouping(x,97,252)){for(;!A.in_grouping(x,97,252);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}return!0}function n(){if(A.in_grouping(x,97,252)){var s=A.cursor;if(e()){if(A.cursor=s,!A.in_grouping(x,97,252))return!0;for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!0;A.cursor++}}return!1}return!0}function i(){var s,r=A.cursor;if(n()){if(A.cursor=r,!A.out_grouping(x,97,252))return;if(s=A.cursor,e()){if(A.cursor=s,!A.in_grouping(x,97,252)||A.cursor>=A.limit)return;A.cursor++}}g=A.cursor}function a(){for(;!A.in_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}for(;!A.out_grouping(x,97,252);){if(A.cursor>=A.limit)return!1;A.cursor++}return!0}function t(){var e=A.cursor;g=A.limit,p=g,v=g,i(),A.cursor=e,a()&&(p=A.cursor,a()&&(v=A.cursor))}function o(){for(var e;;){if(A.bra=A.cursor,e=A.find_among(k,6))switch(A.ket=A.cursor,e){case 1:A.slice_from("a");continue;case 2:A.slice_from("e");continue;case 3:A.slice_from("i");continue;case 4:A.slice_from("o");continue;case 5:A.slice_from("u");continue;case 6:if(A.cursor>=A.limit)break;A.cursor++;continue}break}}function u(){return g<=A.cursor}function w(){return p<=A.cursor}function c(){return v<=A.cursor}function m(){var e;if(A.ket=A.cursor,A.find_among_b(y,13)&&(A.bra=A.cursor,(e=A.find_among_b(q,11))&&u()))switch(e){case 1:A.bra=A.cursor,A.slice_from("iendo");break;case 2:A.bra=A.cursor,A.slice_from("ando");break;case 3:A.bra=A.cursor,A.slice_from("ar");break;case 4:A.bra=A.cursor,A.slice_from("er");break;case 5:A.bra=A.cursor,A.slice_from("ir");break;case 6:A.slice_del();break;case 7:A.eq_s_b(1,"u")&&A.slice_del()}}function l(e,s){if(!c())return!0;A.slice_del(),A.ket=A.cursor;var r=A.find_among_b(e,s);return r&&(A.bra=A.cursor,1==r&&c()&&A.slice_del()),!1}function d(e){return!c()||(A.slice_del(),A.ket=A.cursor,A.eq_s_b(2,e)&&(A.bra=A.cursor,c()&&A.slice_del()),!1)}function b(){var e;if(A.ket=A.cursor,e=A.find_among_b(S,46)){switch(A.bra=A.cursor,e){case 1:if(!c())return!1;A.slice_del();break;case 2:if(d("ic"))return!1;break;case 3:if(!c())return!1;A.slice_from("log");break;case 4:if(!c())return!1;A.slice_from("u");break;case 5:if(!c())return!1;A.slice_from("ente");break;case 6:if(!w())return!1;A.slice_del(),A.ket=A.cursor,e=A.find_among_b(C,4),e&&(A.bra=A.cursor,c()&&(A.slice_del(),1==e&&(A.ket=A.cursor,A.eq_s_b(2,"at")&&(A.bra=A.cursor,c()&&A.slice_del()))));break;case 7:if(l(P,3))return!1;break;case 8:if(l(F,3))return!1;break;case 9:if(d("at"))return!1}return!0}return!1}function f(){var e,s;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(W,12),A.limit_backward=s,e)){if(A.bra=A.cursor,1==e){if(!A.eq_s_b(1,"u"))return!1;A.slice_del()}return!0}return!1}function _(){var e,s,r,n;if(A.cursor>=g&&(s=A.limit_backward,A.limit_backward=g,A.ket=A.cursor,e=A.find_among_b(L,96),A.limit_backward=s,e))switch(A.bra=A.cursor,e){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"u")?(n=A.limit-A.cursor,A.eq_s_b(1,"g")?A.cursor=A.limit-n:A.cursor=A.limit-r):A.cursor=A.limit-r,A.bra=A.cursor;case 2:A.slice_del()}}function h(){var e,s;if(A.ket=A.cursor,e=A.find_among_b(z,8))switch(A.bra=A.cursor,e){case 1:u()&&A.slice_del();break;case 2:u()&&(A.slice_del(),A.ket=A.cursor,A.eq_s_b(1,"u")&&(A.bra=A.cursor,s=A.limit-A.cursor,A.eq_s_b(1,"g")&&(A.cursor=A.limit-s,u()&&A.slice_del())))}}var v,p,g,k=[new s("",-1,6),new s("á",0,1),new s("é",0,2),new s("í",0,3),new s("ó",0,4),new s("ú",0,5)],y=[new s("la",-1,-1),new s("sela",0,-1),new s("le",-1,-1),new s("me",-1,-1),new s("se",-1,-1),new s("lo",-1,-1),new s("selo",5,-1),new s("las",-1,-1),new s("selas",7,-1),new s("les",-1,-1),new s("los",-1,-1),new s("selos",10,-1),new s("nos",-1,-1)],q=[new s("ando",-1,6),new s("iendo",-1,6),new s("yendo",-1,7),new s("ándo",-1,2),new s("iéndo",-1,1),new s("ar",-1,6),new s("er",-1,6),new s("ir",-1,6),new s("ár",-1,3),new s("ér",-1,4),new s("ír",-1,5)],C=[new s("ic",-1,-1),new s("ad",-1,-1),new s("os",-1,-1),new s("iv",-1,1)],P=[new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,1)],F=[new s("ic",-1,1),new s("abil",-1,1),new s("iv",-1,1)],S=[new s("ica",-1,1),new s("ancia",-1,2),new s("encia",-1,5),new s("adora",-1,2),new s("osa",-1,1),new s("ista",-1,1),new s("iva",-1,9),new s("anza",-1,1),new s("logía",-1,3),new s("idad",-1,8),new s("able",-1,1),new s("ible",-1,1),new s("ante",-1,2),new s("mente",-1,7),new s("amente",13,6),new s("ación",-1,2),new s("ución",-1,4),new s("ico",-1,1),new s("ismo",-1,1),new s("oso",-1,1),new s("amiento",-1,1),new s("imiento",-1,1),new s("ivo",-1,9),new s("ador",-1,2),new s("icas",-1,1),new s("ancias",-1,2),new s("encias",-1,5),new s("adoras",-1,2),new s("osas",-1,1),new s("istas",-1,1),new s("ivas",-1,9),new s("anzas",-1,1),new s("logías",-1,3),new s("idades",-1,8),new s("ables",-1,1),new s("ibles",-1,1),new s("aciones",-1,2),new s("uciones",-1,4),new s("adores",-1,2),new s("antes",-1,2),new s("icos",-1,1),new s("ismos",-1,1),new s("osos",-1,1),new s("amientos",-1,1),new s("imientos",-1,1),new s("ivos",-1,9)],W=[new s("ya",-1,1),new s("ye",-1,1),new s("yan",-1,1),new s("yen",-1,1),new s("yeron",-1,1),new s("yendo",-1,1),new s("yo",-1,1),new s("yas",-1,1),new s("yes",-1,1),new s("yais",-1,1),new s("yamos",-1,1),new s("yó",-1,1)],L=[new s("aba",-1,2),new s("ada",-1,2),new s("ida",-1,2),new s("ara",-1,2),new s("iera",-1,2),new s("ía",-1,2),new s("aría",5,2),new s("ería",5,2),new s("iría",5,2),new s("ad",-1,2),new s("ed",-1,2),new s("id",-1,2),new s("ase",-1,2),new s("iese",-1,2),new s("aste",-1,2),new s("iste",-1,2),new s("an",-1,2),new s("aban",16,2),new s("aran",16,2),new s("ieran",16,2),new s("ían",16,2),new s("arían",20,2),new s("erían",20,2),new s("irían",20,2),new s("en",-1,1),new s("asen",24,2),new s("iesen",24,2),new s("aron",-1,2),new s("ieron",-1,2),new s("arán",-1,2),new s("erán",-1,2),new s("irán",-1,2),new s("ado",-1,2),new s("ido",-1,2),new s("ando",-1,2),new s("iendo",-1,2),new s("ar",-1,2),new s("er",-1,2),new s("ir",-1,2),new s("as",-1,2),new s("abas",39,2),new s("adas",39,2),new s("idas",39,2),new s("aras",39,2),new s("ieras",39,2),new s("ías",39,2),new s("arías",45,2),new s("erías",45,2),new s("irías",45,2),new s("es",-1,1),new s("ases",49,2),new s("ieses",49,2),new s("abais",-1,2),new s("arais",-1,2),new s("ierais",-1,2),new s("íais",-1,2),new s("aríais",55,2),new s("eríais",55,2),new s("iríais",55,2),new s("aseis",-1,2),new s("ieseis",-1,2),new s("asteis",-1,2),new s("isteis",-1,2),new s("áis",-1,2),new s("éis",-1,1),new s("aréis",64,2),new s("eréis",64,2),new s("iréis",64,2),new s("ados",-1,2),new s("idos",-1,2),new s("amos",-1,2),new s("ábamos",70,2),new s("áramos",70,2),new s("iéramos",70,2),new s("íamos",70,2),new s("aríamos",74,2),new s("eríamos",74,2),new s("iríamos",74,2),new s("emos",-1,1),new s("aremos",78,2),new s("eremos",78,2),new s("iremos",78,2),new s("ásemos",78,2),new s("iésemos",78,2),new s("imos",-1,2),new s("arás",-1,2),new s("erás",-1,2),new s("irás",-1,2),new s("ís",-1,2),new s("ará",-1,2),new s("erá",-1,2),new s("irá",-1,2),new s("aré",-1,2),new s("eré",-1,2),new s("iré",-1,2),new s("ió",-1,2)],z=[new s("a",-1,1),new s("e",-1,2),new s("o",-1,1),new s("os",-1,1),new s("á",-1,1),new s("é",-1,2),new s("í",-1,1),new s("ó",-1,1)],x=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,4,10],A=new r;this.setCurrent=function(e){A.setCurrent(e)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return t(),A.limit_backward=e,A.cursor=A.limit,m(),A.cursor=A.limit,b()||(A.cursor=A.limit,f()||(A.cursor=A.limit,_())),A.cursor=A.limit,h(),A.cursor=A.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.es.stemmer,"stemmer-es"),e.es.stopWordFilter=e.generateStopWordFilter("a al algo algunas algunos ante antes como con contra cual cuando de del desde donde durante e el ella ellas ellos en entre era erais eran eras eres es esa esas ese eso esos esta estaba estabais estaban estabas estad estada estadas estado estados estamos estando estar estaremos estará estarán estarás estaré estaréis estaría estaríais estaríamos estarían estarías estas este estemos esto estos estoy estuve estuviera estuvierais estuvieran estuvieras estuvieron estuviese estuvieseis estuviesen estuvieses estuvimos estuviste estuvisteis estuviéramos estuviésemos estuvo está estábamos estáis están estás esté estéis estén estés fue fuera fuerais fueran fueras fueron fuese fueseis fuesen fueses fui fuimos fuiste fuisteis fuéramos fuésemos ha habida habidas habido habidos habiendo habremos habrá habrán habrás habré habréis habría habríais habríamos habrían habrías habéis había habíais habíamos habían habías han has hasta hay haya hayamos hayan hayas hayáis he hemos hube hubiera hubierais hubieran hubieras hubieron hubiese hubieseis hubiesen hubieses hubimos hubiste hubisteis hubiéramos hubiésemos hubo la las le les lo los me mi mis mucho muchos muy más mí mía mías mío míos nada ni no nos nosotras nosotros nuestra nuestras nuestro nuestros o os otra otras otro otros para pero poco por porque que quien quienes qué se sea seamos sean seas seremos será serán serás seré seréis sería seríais seríamos serían serías seáis sido siendo sin sobre sois somos son soy su sus suya suyas suyo suyos sí también tanto te tendremos tendrá tendrán tendrás tendré tendréis tendría tendríais tendríamos tendrían tendrías tened tenemos tenga tengamos tengan tengas tengo tengáis tenida tenidas tenido tenidos teniendo tenéis tenía teníais teníamos tenían tenías ti tiene tienen tienes todo todos tu tus tuve tuviera tuvierais tuvieran tuvieras tuvieron tuviese tuvieseis tuviesen tuvieses tuvimos tuviste tuvisteis tuviéramos tuviésemos tuvo tuya tuyas tuyo tuyos tú un una uno unos vosotras vosotros vuestra vuestras vuestro vuestros y ya yo él éramos".split(" ")),e.Pipeline.registerFunction(e.es.stopWordFilter,"stopWordFilter-es")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.fi.min.js b/assets/javascripts/lunr/min/lunr.fi.min.js new file mode 100644 index 0000000..29f5dfc --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.fi.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Finnish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=function(){var e=i.stemmerSupport.Among,r=i.stemmerSupport.SnowballProgram,n=new function(){function i(){f=A.limit,d=f,n()||(f=A.cursor,n()||(d=A.cursor))}function n(){for(var i;;){if(i=A.cursor,A.in_grouping(W,97,246))break;if(A.cursor=i,i>=A.limit)return!0;A.cursor++}for(A.cursor=i;!A.out_grouping(W,97,246);){if(A.cursor>=A.limit)return!0;A.cursor++}return!1}function t(){return d<=A.cursor}function s(){var i,e;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(h,10)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.in_grouping_b(x,97,246))return;break;case 2:if(!t())return}A.slice_del()}else A.limit_backward=e}function o(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(v,9))switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:r=A.limit-A.cursor,A.eq_s_b(1,"k")||(A.cursor=A.limit-r,A.slice_del());break;case 2:A.slice_del(),A.ket=A.cursor,A.eq_s_b(3,"kse")&&(A.bra=A.cursor,A.slice_from("ksi"));break;case 3:A.slice_del();break;case 4:A.find_among_b(p,6)&&A.slice_del();break;case 5:A.find_among_b(g,6)&&A.slice_del();break;case 6:A.find_among_b(j,2)&&A.slice_del()}else A.limit_backward=e}function l(){return A.find_among_b(q,7)}function a(){return A.eq_s_b(1,"i")&&A.in_grouping_b(L,97,246)}function u(){var i,e,r;if(A.cursor>=f)if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,i=A.find_among_b(C,30)){switch(A.bra=A.cursor,A.limit_backward=e,i){case 1:if(!A.eq_s_b(1,"a"))return;break;case 2:case 9:if(!A.eq_s_b(1,"e"))return;break;case 3:if(!A.eq_s_b(1,"i"))return;break;case 4:if(!A.eq_s_b(1,"o"))return;break;case 5:if(!A.eq_s_b(1,"ä"))return;break;case 6:if(!A.eq_s_b(1,"ö"))return;break;case 7:if(r=A.limit-A.cursor,!l()&&(A.cursor=A.limit-r,!A.eq_s_b(2,"ie"))){A.cursor=A.limit-r;break}if(A.cursor=A.limit-r,A.cursor<=A.limit_backward){A.cursor=A.limit-r;break}A.cursor--,A.bra=A.cursor;break;case 8:if(!A.in_grouping_b(W,97,246)||!A.out_grouping_b(W,97,246))return}A.slice_del(),k=!0}else A.limit_backward=e}function c(){var i,e,r;if(A.cursor>=d)if(e=A.limit_backward,A.limit_backward=d,A.ket=A.cursor,i=A.find_among_b(P,14)){if(A.bra=A.cursor,A.limit_backward=e,1==i){if(r=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-r}A.slice_del()}else A.limit_backward=e}function m(){var i;A.cursor>=f&&(i=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.find_among_b(F,2)?(A.bra=A.cursor,A.limit_backward=i,A.slice_del()):A.limit_backward=i)}function w(){var i,e,r,n,t,s;if(A.cursor>=f){if(e=A.limit_backward,A.limit_backward=f,A.ket=A.cursor,A.eq_s_b(1,"t")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.in_grouping_b(W,97,246)&&(A.cursor=A.limit-r,A.slice_del(),A.limit_backward=e,n=A.limit-A.cursor,A.cursor>=d&&(A.cursor=d,t=A.limit_backward,A.limit_backward=A.cursor,A.cursor=A.limit-n,A.ket=A.cursor,i=A.find_among_b(S,2))))){if(A.bra=A.cursor,A.limit_backward=t,1==i){if(s=A.limit-A.cursor,A.eq_s_b(2,"po"))return;A.cursor=A.limit-s}return void A.slice_del()}A.limit_backward=e}}function _(){var i,e,r,n;if(A.cursor>=f){for(i=A.limit_backward,A.limit_backward=f,e=A.limit-A.cursor,l()&&(A.cursor=A.limit-e,A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.in_grouping_b(y,97,228)&&(A.bra=A.cursor,A.out_grouping_b(W,97,246)&&A.slice_del()),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"j")&&(A.bra=A.cursor,r=A.limit-A.cursor,A.eq_s_b(1,"o")?A.slice_del():(A.cursor=A.limit-r,A.eq_s_b(1,"u")&&A.slice_del())),A.cursor=A.limit-e,A.ket=A.cursor,A.eq_s_b(1,"o")&&(A.bra=A.cursor,A.eq_s_b(1,"j")&&A.slice_del()),A.cursor=A.limit-e,A.limit_backward=i;;){if(n=A.limit-A.cursor,A.out_grouping_b(W,97,246)){A.cursor=A.limit-n;break}if(A.cursor=A.limit-n,A.cursor<=A.limit_backward)return;A.cursor--}A.ket=A.cursor,A.cursor>A.limit_backward&&(A.cursor--,A.bra=A.cursor,b=A.slice_to(),A.eq_v_b(b)&&A.slice_del())}}var k,b,d,f,h=[new e("pa",-1,1),new e("sti",-1,2),new e("kaan",-1,1),new e("han",-1,1),new e("kin",-1,1),new e("hän",-1,1),new e("kään",-1,1),new e("ko",-1,1),new e("pä",-1,1),new e("kö",-1,1)],p=[new e("lla",-1,-1),new e("na",-1,-1),new e("ssa",-1,-1),new e("ta",-1,-1),new e("lta",3,-1),new e("sta",3,-1)],g=[new e("llä",-1,-1),new e("nä",-1,-1),new e("ssä",-1,-1),new e("tä",-1,-1),new e("ltä",3,-1),new e("stä",3,-1)],j=[new e("lle",-1,-1),new e("ine",-1,-1)],v=[new e("nsa",-1,3),new e("mme",-1,3),new e("nne",-1,3),new e("ni",-1,2),new e("si",-1,1),new e("an",-1,4),new e("en",-1,6),new e("än",-1,5),new e("nsä",-1,3)],q=[new e("aa",-1,-1),new e("ee",-1,-1),new e("ii",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1),new e("ää",-1,-1),new e("öö",-1,-1)],C=[new e("a",-1,8),new e("lla",0,-1),new e("na",0,-1),new e("ssa",0,-1),new e("ta",0,-1),new e("lta",4,-1),new e("sta",4,-1),new e("tta",4,9),new e("lle",-1,-1),new e("ine",-1,-1),new e("ksi",-1,-1),new e("n",-1,7),new e("han",11,1),new e("den",11,-1,a),new e("seen",11,-1,l),new e("hen",11,2),new e("tten",11,-1,a),new e("hin",11,3),new e("siin",11,-1,a),new e("hon",11,4),new e("hän",11,5),new e("hön",11,6),new e("ä",-1,8),new e("llä",22,-1),new e("nä",22,-1),new e("ssä",22,-1),new e("tä",22,-1),new e("ltä",26,-1),new e("stä",26,-1),new e("ttä",26,9)],P=[new e("eja",-1,-1),new e("mma",-1,1),new e("imma",1,-1),new e("mpa",-1,1),new e("impa",3,-1),new e("mmi",-1,1),new e("immi",5,-1),new e("mpi",-1,1),new e("impi",7,-1),new e("ejä",-1,-1),new e("mmä",-1,1),new e("immä",10,-1),new e("mpä",-1,1),new e("impä",12,-1)],F=[new e("i",-1,-1),new e("j",-1,-1)],S=[new e("mma",-1,1),new e("imma",0,-1)],y=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],W=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],x=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],A=new r;this.setCurrent=function(i){A.setCurrent(i)},this.getCurrent=function(){return A.getCurrent()},this.stem=function(){var e=A.cursor;return i(),k=!1,A.limit_backward=e,A.cursor=A.limit,s(),A.cursor=A.limit,o(),A.cursor=A.limit,u(),A.cursor=A.limit,c(),A.cursor=A.limit,k?(m(),A.cursor=A.limit):(A.cursor=A.limit,w(),A.cursor=A.limit),_(),!0}};return function(i){return"function"==typeof i.update?i.update(function(i){return n.setCurrent(i),n.stem(),n.getCurrent()}):(n.setCurrent(i),n.stem(),n.getCurrent())}}(),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.fr.min.js b/assets/javascripts/lunr/min/lunr.fr.min.js new file mode 100644 index 0000000..68cd009 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.fr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `French` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,s){return!(!W.eq_s(1,e)||(W.ket=W.cursor,!W.in_grouping(F,97,251)))&&(W.slice_from(r),W.cursor=s,!0)}function i(e,r,s){return!!W.eq_s(1,e)&&(W.ket=W.cursor,W.slice_from(r),W.cursor=s,!0)}function n(){for(var r,s;;){if(r=W.cursor,W.in_grouping(F,97,251)){if(W.bra=W.cursor,s=W.cursor,e("u","U",r))continue;if(W.cursor=s,e("i","I",r))continue;if(W.cursor=s,i("y","Y",r))continue}if(W.cursor=r,W.bra=r,!e("y","Y",r)){if(W.cursor=r,W.eq_s(1,"q")&&(W.bra=W.cursor,i("u","U",r)))continue;if(W.cursor=r,r>=W.limit)return;W.cursor++}}}function t(){for(;!W.in_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}for(;!W.out_grouping(F,97,251);){if(W.cursor>=W.limit)return!0;W.cursor++}return!1}function u(){var e=W.cursor;if(q=W.limit,g=q,p=q,W.in_grouping(F,97,251)&&W.in_grouping(F,97,251)&&W.cursor=W.limit){W.cursor=q;break}W.cursor++}while(!W.in_grouping(F,97,251))}q=W.cursor,W.cursor=e,t()||(g=W.cursor,t()||(p=W.cursor))}function o(){for(var e,r;;){if(r=W.cursor,W.bra=r,!(e=W.find_among(h,4)))break;switch(W.ket=W.cursor,e){case 1:W.slice_from("i");break;case 2:W.slice_from("u");break;case 3:W.slice_from("y");break;case 4:if(W.cursor>=W.limit)return;W.cursor++}}}function c(){return q<=W.cursor}function a(){return g<=W.cursor}function l(){return p<=W.cursor}function w(){var e,r;if(W.ket=W.cursor,e=W.find_among_b(C,43)){switch(W.bra=W.cursor,e){case 1:if(!l())return!1;W.slice_del();break;case 2:if(!l())return!1;W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")&&(W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU"));break;case 3:if(!l())return!1;W.slice_from("log");break;case 4:if(!l())return!1;W.slice_from("u");break;case 5:if(!l())return!1;W.slice_from("ent");break;case 6:if(!c())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(z,6))switch(W.bra=W.cursor,e){case 1:l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&W.slice_del()));break;case 2:l()?W.slice_del():a()&&W.slice_from("eux");break;case 3:l()&&W.slice_del();break;case 4:c()&&W.slice_from("i")}break;case 7:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,e=W.find_among_b(y,3))switch(W.bra=W.cursor,e){case 1:l()?W.slice_del():W.slice_from("abl");break;case 2:l()?W.slice_del():W.slice_from("iqU");break;case 3:l()&&W.slice_del()}break;case 8:if(!l())return!1;if(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"at")&&(W.bra=W.cursor,l()&&(W.slice_del(),W.ket=W.cursor,W.eq_s_b(2,"ic")))){W.bra=W.cursor,l()?W.slice_del():W.slice_from("iqU");break}break;case 9:W.slice_from("eau");break;case 10:if(!a())return!1;W.slice_from("al");break;case 11:if(l())W.slice_del();else{if(!a())return!1;W.slice_from("eux")}break;case 12:if(!a()||!W.out_grouping_b(F,97,251))return!1;W.slice_del();break;case 13:return c()&&W.slice_from("ant"),!1;case 14:return c()&&W.slice_from("ent"),!1;case 15:return r=W.limit-W.cursor,W.in_grouping_b(F,97,251)&&c()&&(W.cursor=W.limit-r,W.slice_del()),!1}return!0}return!1}function f(){var e,r;if(W.cursor=q){if(s=W.limit_backward,W.limit_backward=q,W.ket=W.cursor,e=W.find_among_b(P,7))switch(W.bra=W.cursor,e){case 1:if(l()){if(i=W.limit-W.cursor,!W.eq_s_b(1,"s")&&(W.cursor=W.limit-i,!W.eq_s_b(1,"t")))break;W.slice_del()}break;case 2:W.slice_from("i");break;case 3:W.slice_del();break;case 4:W.eq_s_b(2,"gu")&&W.slice_del()}W.limit_backward=s}}function b(){var e=W.limit-W.cursor;W.find_among_b(U,5)&&(W.cursor=W.limit-e,W.ket=W.cursor,W.cursor>W.limit_backward&&(W.cursor--,W.bra=W.cursor,W.slice_del()))}function d(){for(var e,r=1;W.out_grouping_b(F,97,251);)r--;if(r<=0){if(W.ket=W.cursor,e=W.limit-W.cursor,!W.eq_s_b(1,"é")&&(W.cursor=W.limit-e,!W.eq_s_b(1,"è")))return;W.bra=W.cursor,W.slice_from("e")}}function k(){if(!w()&&(W.cursor=W.limit,!f()&&(W.cursor=W.limit,!m())))return W.cursor=W.limit,void _();W.cursor=W.limit,W.ket=W.cursor,W.eq_s_b(1,"Y")?(W.bra=W.cursor,W.slice_from("i")):(W.cursor=W.limit,W.eq_s_b(1,"ç")&&(W.bra=W.cursor,W.slice_from("c")))}var p,g,q,v=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],h=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],z=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],y=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],C=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],x=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],I=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],P=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],U=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],F=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],S=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],W=new s;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){var e=W.cursor;return n(),W.cursor=e,u(),W.limit_backward=e,W.cursor=W.limit,k(),W.cursor=W.limit,b(),W.cursor=W.limit,d(),W.cursor=W.limit_backward,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.hi.min.js b/assets/javascripts/lunr/min/lunr.hi.min.js new file mode 100644 index 0000000..7dbc414 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.hi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.hu.min.js b/assets/javascripts/lunr/min/lunr.hu.min.js new file mode 100644 index 0000000..ed9d909 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.hu.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Hungarian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,n=L.cursor;if(d=L.limit,L.in_grouping(W,97,252))for(;;){if(e=L.cursor,L.out_grouping(W,97,252))return L.cursor=e,L.find_among(g,8)||(L.cursor=e,e=L.limit)return void(d=e);L.cursor++}if(L.cursor=n,L.out_grouping(W,97,252)){for(;!L.in_grouping(W,97,252);){if(L.cursor>=L.limit)return;L.cursor++}d=L.cursor}}function i(){return d<=L.cursor}function a(){var e;if(L.ket=L.cursor,(e=L.find_among_b(h,2))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e")}}function t(){var e=L.limit-L.cursor;return!!L.find_among_b(p,23)&&(L.cursor=L.limit-e,!0)}function s(){if(L.cursor>L.limit_backward){L.cursor--,L.ket=L.cursor;var e=L.cursor-1;L.limit_backward<=e&&e<=L.limit&&(L.cursor=e,L.bra=e,L.slice_del())}}function c(){var e;if(L.ket=L.cursor,(e=L.find_among_b(_,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function o(){L.ket=L.cursor,L.find_among_b(v,44)&&(L.bra=L.cursor,i()&&(L.slice_del(),a()))}function w(){var e;if(L.ket=L.cursor,(e=L.find_among_b(z,3))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("e");break;case 2:case 3:L.slice_from("a")}}function l(){var e;if(L.ket=L.cursor,(e=L.find_among_b(y,6))&&(L.bra=L.cursor,i()))switch(e){case 1:case 2:L.slice_del();break;case 3:L.slice_from("a");break;case 4:L.slice_from("e")}}function u(){var e;if(L.ket=L.cursor,(e=L.find_among_b(j,2))&&(L.bra=L.cursor,i())){if((1==e||2==e)&&!t())return;L.slice_del(),s()}}function m(){var e;if(L.ket=L.cursor,(e=L.find_among_b(C,7))&&(L.bra=L.cursor,i()))switch(e){case 1:L.slice_from("a");break;case 2:L.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:L.slice_del()}}function k(){var e;if(L.ket=L.cursor,(e=L.find_among_b(P,12))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 9:L.slice_del();break;case 2:case 5:case 8:L.slice_from("e");break;case 3:case 6:L.slice_from("a")}}function f(){var e;if(L.ket=L.cursor,(e=L.find_among_b(F,31))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:L.slice_del();break;case 2:case 5:case 10:case 14:case 19:L.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:L.slice_from("e")}}function b(){var e;if(L.ket=L.cursor,(e=L.find_among_b(S,42))&&(L.bra=L.cursor,i()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:L.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:L.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:L.slice_from("e")}}var d,g=[new n("cs",-1,-1),new n("dzs",-1,-1),new n("gy",-1,-1),new n("ly",-1,-1),new n("ny",-1,-1),new n("sz",-1,-1),new n("ty",-1,-1),new n("zs",-1,-1)],h=[new n("á",-1,1),new n("é",-1,2)],p=[new n("bb",-1,-1),new n("cc",-1,-1),new n("dd",-1,-1),new n("ff",-1,-1),new n("gg",-1,-1),new n("jj",-1,-1),new n("kk",-1,-1),new n("ll",-1,-1),new n("mm",-1,-1),new n("nn",-1,-1),new n("pp",-1,-1),new n("rr",-1,-1),new n("ccs",-1,-1),new n("ss",-1,-1),new n("zzs",-1,-1),new n("tt",-1,-1),new n("vv",-1,-1),new n("ggy",-1,-1),new n("lly",-1,-1),new n("nny",-1,-1),new n("tty",-1,-1),new n("ssz",-1,-1),new n("zz",-1,-1)],_=[new n("al",-1,1),new n("el",-1,2)],v=[new n("ba",-1,-1),new n("ra",-1,-1),new n("be",-1,-1),new n("re",-1,-1),new n("ig",-1,-1),new n("nak",-1,-1),new n("nek",-1,-1),new n("val",-1,-1),new n("vel",-1,-1),new n("ul",-1,-1),new n("nál",-1,-1),new n("nél",-1,-1),new n("ból",-1,-1),new n("ról",-1,-1),new n("tól",-1,-1),new n("bõl",-1,-1),new n("rõl",-1,-1),new n("tõl",-1,-1),new n("ül",-1,-1),new n("n",-1,-1),new n("an",19,-1),new n("ban",20,-1),new n("en",19,-1),new n("ben",22,-1),new n("képpen",22,-1),new n("on",19,-1),new n("ön",19,-1),new n("képp",-1,-1),new n("kor",-1,-1),new n("t",-1,-1),new n("at",29,-1),new n("et",29,-1),new n("ként",29,-1),new n("anként",32,-1),new n("enként",32,-1),new n("onként",32,-1),new n("ot",29,-1),new n("ért",29,-1),new n("öt",29,-1),new n("hez",-1,-1),new n("hoz",-1,-1),new n("höz",-1,-1),new n("vá",-1,-1),new n("vé",-1,-1)],z=[new n("án",-1,2),new n("én",-1,1),new n("ánként",-1,3)],y=[new n("stul",-1,2),new n("astul",0,1),new n("ástul",0,3),new n("stül",-1,2),new n("estül",3,1),new n("éstül",3,4)],j=[new n("á",-1,1),new n("é",-1,2)],C=[new n("k",-1,7),new n("ak",0,4),new n("ek",0,6),new n("ok",0,5),new n("ák",0,1),new n("ék",0,2),new n("ök",0,3)],P=[new n("éi",-1,7),new n("áéi",0,6),new n("ééi",0,5),new n("é",-1,9),new n("ké",3,4),new n("aké",4,1),new n("eké",4,1),new n("oké",4,1),new n("áké",4,3),new n("éké",4,2),new n("öké",4,1),new n("éé",3,8)],F=[new n("a",-1,18),new n("ja",0,17),new n("d",-1,16),new n("ad",2,13),new n("ed",2,13),new n("od",2,13),new n("ád",2,14),new n("éd",2,15),new n("öd",2,13),new n("e",-1,18),new n("je",9,17),new n("nk",-1,4),new n("unk",11,1),new n("ánk",11,2),new n("énk",11,3),new n("ünk",11,1),new n("uk",-1,8),new n("juk",16,7),new n("ájuk",17,5),new n("ük",-1,8),new n("jük",19,7),new n("éjük",20,6),new n("m",-1,12),new n("am",22,9),new n("em",22,9),new n("om",22,9),new n("ám",22,10),new n("ém",22,11),new n("o",-1,18),new n("á",-1,19),new n("é",-1,20)],S=[new n("id",-1,10),new n("aid",0,9),new n("jaid",1,6),new n("eid",0,9),new n("jeid",3,6),new n("áid",0,7),new n("éid",0,8),new n("i",-1,15),new n("ai",7,14),new n("jai",8,11),new n("ei",7,14),new n("jei",10,11),new n("ái",7,12),new n("éi",7,13),new n("itek",-1,24),new n("eitek",14,21),new n("jeitek",15,20),new n("éitek",14,23),new n("ik",-1,29),new n("aik",18,26),new n("jaik",19,25),new n("eik",18,26),new n("jeik",21,25),new n("áik",18,27),new n("éik",18,28),new n("ink",-1,20),new n("aink",25,17),new n("jaink",26,16),new n("eink",25,17),new n("jeink",28,16),new n("áink",25,18),new n("éink",25,19),new n("aitok",-1,21),new n("jaitok",32,20),new n("áitok",-1,22),new n("im",-1,5),new n("aim",35,4),new n("jaim",36,1),new n("eim",35,4),new n("jeim",38,1),new n("áim",35,2),new n("éim",35,3)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var n=L.cursor;return e(),L.limit_backward=n,L.cursor=L.limit,c(),L.cursor=L.limit,o(),L.cursor=L.limit,w(),L.cursor=L.limit,l(),L.cursor=L.limit,u(),L.cursor=L.limit,k(),L.cursor=L.limit,f(),L.cursor=L.limit,b(),L.cursor=L.limit,m(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.it.min.js b/assets/javascripts/lunr/min/lunr.it.min.js new file mode 100644 index 0000000..344b6a3 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.it.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Italian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.it=function(){this.pipeline.reset(),this.pipeline.add(e.it.trimmer,e.it.stopWordFilter,e.it.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.it.stemmer))},e.it.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.it.trimmer=e.trimmerSupport.generateTrimmer(e.it.wordCharacters),e.Pipeline.registerFunction(e.it.trimmer,"trimmer-it"),e.it.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(e,r,n){return!(!x.eq_s(1,e)||(x.ket=x.cursor,!x.in_grouping(L,97,249)))&&(x.slice_from(r),x.cursor=n,!0)}function i(){for(var r,n,i,o,t=x.cursor;;){if(x.bra=x.cursor,r=x.find_among(h,7))switch(x.ket=x.cursor,r){case 1:x.slice_from("à");continue;case 2:x.slice_from("è");continue;case 3:x.slice_from("ì");continue;case 4:x.slice_from("ò");continue;case 5:x.slice_from("ù");continue;case 6:x.slice_from("qU");continue;case 7:if(x.cursor>=x.limit)break;x.cursor++;continue}break}for(x.cursor=t;;)for(n=x.cursor;;){if(i=x.cursor,x.in_grouping(L,97,249)){if(x.bra=x.cursor,o=x.cursor,e("u","U",i))break;if(x.cursor=o,e("i","I",i))break}if(x.cursor=i,x.cursor>=x.limit)return void(x.cursor=n);x.cursor++}}function o(e){if(x.cursor=e,!x.in_grouping(L,97,249))return!1;for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function t(){if(x.in_grouping(L,97,249)){var e=x.cursor;if(x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return o(e);x.cursor++}return!0}return o(e)}return!1}function s(){var e,r=x.cursor;if(!t()){if(x.cursor=r,!x.out_grouping(L,97,249))return;if(e=x.cursor,x.out_grouping(L,97,249)){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return x.cursor=e,void(x.in_grouping(L,97,249)&&x.cursor=x.limit)return;x.cursor++}k=x.cursor}function a(){for(;!x.in_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}for(;!x.out_grouping(L,97,249);){if(x.cursor>=x.limit)return!1;x.cursor++}return!0}function u(){var e=x.cursor;k=x.limit,p=k,g=k,s(),x.cursor=e,a()&&(p=x.cursor,a()&&(g=x.cursor))}function c(){for(var e;;){if(x.bra=x.cursor,!(e=x.find_among(q,3)))break;switch(x.ket=x.cursor,e){case 1:x.slice_from("i");break;case 2:x.slice_from("u");break;case 3:if(x.cursor>=x.limit)return;x.cursor++}}}function w(){return k<=x.cursor}function l(){return p<=x.cursor}function m(){return g<=x.cursor}function f(){var e;if(x.ket=x.cursor,x.find_among_b(C,37)&&(x.bra=x.cursor,(e=x.find_among_b(z,5))&&w()))switch(e){case 1:x.slice_del();break;case 2:x.slice_from("e")}}function v(){var e;if(x.ket=x.cursor,!(e=x.find_among_b(S,51)))return!1;switch(x.bra=x.cursor,e){case 1:if(!m())return!1;x.slice_del();break;case 2:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del());break;case 3:if(!m())return!1;x.slice_from("log");break;case 4:if(!m())return!1;x.slice_from("u");break;case 5:if(!m())return!1;x.slice_from("ente");break;case 6:if(!w())return!1;x.slice_del();break;case 7:if(!l())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(P,4),e&&(x.bra=x.cursor,m()&&(x.slice_del(),1==e&&(x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&x.slice_del()))));break;case 8:if(!m())return!1;x.slice_del(),x.ket=x.cursor,e=x.find_among_b(F,3),e&&(x.bra=x.cursor,1==e&&m()&&x.slice_del());break;case 9:if(!m())return!1;x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"at")&&(x.bra=x.cursor,m()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(2,"ic")&&(x.bra=x.cursor,m()&&x.slice_del())))}return!0}function b(){var e,r;x.cursor>=k&&(r=x.limit_backward,x.limit_backward=k,x.ket=x.cursor,e=x.find_among_b(W,87),e&&(x.bra=x.cursor,1==e&&x.slice_del()),x.limit_backward=r)}function d(){var e=x.limit-x.cursor;if(x.ket=x.cursor,x.in_grouping_b(y,97,242)&&(x.bra=x.cursor,w()&&(x.slice_del(),x.ket=x.cursor,x.eq_s_b(1,"i")&&(x.bra=x.cursor,w()))))return void x.slice_del();x.cursor=x.limit-e}function _(){d(),x.ket=x.cursor,x.eq_s_b(1,"h")&&(x.bra=x.cursor,x.in_grouping_b(U,99,103)&&w()&&x.slice_del())}var g,p,k,h=[new r("",-1,7),new r("qu",0,6),new r("á",0,1),new r("é",0,2),new r("í",0,3),new r("ó",0,4),new r("ú",0,5)],q=[new r("",-1,3),new r("I",0,1),new r("U",0,2)],C=[new r("la",-1,-1),new r("cela",0,-1),new r("gliela",0,-1),new r("mela",0,-1),new r("tela",0,-1),new r("vela",0,-1),new r("le",-1,-1),new r("cele",6,-1),new r("gliele",6,-1),new r("mele",6,-1),new r("tele",6,-1),new r("vele",6,-1),new r("ne",-1,-1),new r("cene",12,-1),new r("gliene",12,-1),new r("mene",12,-1),new r("sene",12,-1),new r("tene",12,-1),new r("vene",12,-1),new r("ci",-1,-1),new r("li",-1,-1),new r("celi",20,-1),new r("glieli",20,-1),new r("meli",20,-1),new r("teli",20,-1),new r("veli",20,-1),new r("gli",20,-1),new r("mi",-1,-1),new r("si",-1,-1),new r("ti",-1,-1),new r("vi",-1,-1),new r("lo",-1,-1),new r("celo",31,-1),new r("glielo",31,-1),new r("melo",31,-1),new r("telo",31,-1),new r("velo",31,-1)],z=[new r("ando",-1,1),new r("endo",-1,1),new r("ar",-1,2),new r("er",-1,2),new r("ir",-1,2)],P=[new r("ic",-1,-1),new r("abil",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],F=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],S=[new r("ica",-1,1),new r("logia",-1,3),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,9),new r("anza",-1,1),new r("enza",-1,5),new r("ice",-1,1),new r("atrice",7,1),new r("iche",-1,1),new r("logie",-1,3),new r("abile",-1,1),new r("ibile",-1,1),new r("usione",-1,4),new r("azione",-1,2),new r("uzione",-1,4),new r("atore",-1,2),new r("ose",-1,1),new r("ante",-1,1),new r("mente",-1,1),new r("amente",19,7),new r("iste",-1,1),new r("ive",-1,9),new r("anze",-1,1),new r("enze",-1,5),new r("ici",-1,1),new r("atrici",25,1),new r("ichi",-1,1),new r("abili",-1,1),new r("ibili",-1,1),new r("ismi",-1,1),new r("usioni",-1,4),new r("azioni",-1,2),new r("uzioni",-1,4),new r("atori",-1,2),new r("osi",-1,1),new r("anti",-1,1),new r("amenti",-1,6),new r("imenti",-1,6),new r("isti",-1,1),new r("ivi",-1,9),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,6),new r("imento",-1,6),new r("ivo",-1,9),new r("ità",-1,8),new r("istà",-1,1),new r("istè",-1,1),new r("istì",-1,1)],W=[new r("isca",-1,1),new r("enda",-1,1),new r("ata",-1,1),new r("ita",-1,1),new r("uta",-1,1),new r("ava",-1,1),new r("eva",-1,1),new r("iva",-1,1),new r("erebbe",-1,1),new r("irebbe",-1,1),new r("isce",-1,1),new r("ende",-1,1),new r("are",-1,1),new r("ere",-1,1),new r("ire",-1,1),new r("asse",-1,1),new r("ate",-1,1),new r("avate",16,1),new r("evate",16,1),new r("ivate",16,1),new r("ete",-1,1),new r("erete",20,1),new r("irete",20,1),new r("ite",-1,1),new r("ereste",-1,1),new r("ireste",-1,1),new r("ute",-1,1),new r("erai",-1,1),new r("irai",-1,1),new r("isci",-1,1),new r("endi",-1,1),new r("erei",-1,1),new r("irei",-1,1),new r("assi",-1,1),new r("ati",-1,1),new r("iti",-1,1),new r("eresti",-1,1),new r("iresti",-1,1),new r("uti",-1,1),new r("avi",-1,1),new r("evi",-1,1),new r("ivi",-1,1),new r("isco",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("Yamo",-1,1),new r("iamo",-1,1),new r("avamo",-1,1),new r("evamo",-1,1),new r("ivamo",-1,1),new r("eremo",-1,1),new r("iremo",-1,1),new r("assimo",-1,1),new r("ammo",-1,1),new r("emmo",-1,1),new r("eremmo",54,1),new r("iremmo",54,1),new r("immo",-1,1),new r("ano",-1,1),new r("iscano",58,1),new r("avano",58,1),new r("evano",58,1),new r("ivano",58,1),new r("eranno",-1,1),new r("iranno",-1,1),new r("ono",-1,1),new r("iscono",65,1),new r("arono",65,1),new r("erono",65,1),new r("irono",65,1),new r("erebbero",-1,1),new r("irebbero",-1,1),new r("assero",-1,1),new r("essero",-1,1),new r("issero",-1,1),new r("ato",-1,1),new r("ito",-1,1),new r("uto",-1,1),new r("avo",-1,1),new r("evo",-1,1),new r("ivo",-1,1),new r("ar",-1,1),new r("ir",-1,1),new r("erà",-1,1),new r("irà",-1,1),new r("erò",-1,1),new r("irò",-1,1)],L=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2,1],y=[17,65,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,8,2],U=[17],x=new n;this.setCurrent=function(e){x.setCurrent(e)},this.getCurrent=function(){return x.getCurrent()},this.stem=function(){var e=x.cursor;return i(),x.cursor=e,u(),x.limit_backward=e,x.cursor=x.limit,f(),x.cursor=x.limit,v()||(x.cursor=x.limit,b()),x.cursor=x.limit,_(),x.cursor=x.limit_backward,c(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.it.stemmer,"stemmer-it"),e.it.stopWordFilter=e.generateStopWordFilter("a abbia abbiamo abbiano abbiate ad agl agli ai al all alla alle allo anche avemmo avendo avesse avessero avessi avessimo aveste avesti avete aveva avevamo avevano avevate avevi avevo avrai avranno avrebbe avrebbero avrei avremmo avremo avreste avresti avrete avrà avrò avuta avute avuti avuto c che chi ci coi col come con contro cui da dagl dagli dai dal dall dalla dalle dallo degl degli dei del dell della delle dello di dov dove e ebbe ebbero ebbi ed era erano eravamo eravate eri ero essendo faccia facciamo facciano facciate faccio facemmo facendo facesse facessero facessi facessimo faceste facesti faceva facevamo facevano facevate facevi facevo fai fanno farai faranno farebbe farebbero farei faremmo faremo fareste faresti farete farà farò fece fecero feci fosse fossero fossi fossimo foste fosti fu fui fummo furono gli ha hai hanno ho i il in io l la le lei li lo loro lui ma mi mia mie miei mio ne negl negli nei nel nell nella nelle nello noi non nostra nostre nostri nostro o per perché più quale quanta quante quanti quanto quella quelle quelli quello questa queste questi questo sarai saranno sarebbe sarebbero sarei saremmo saremo sareste saresti sarete sarà sarò se sei si sia siamo siano siate siete sono sta stai stando stanno starai staranno starebbe starebbero starei staremmo staremo stareste staresti starete starà starò stava stavamo stavano stavate stavi stavo stemmo stesse stessero stessi stessimo steste stesti stette stettero stetti stia stiamo stiano stiate sto su sua sue sugl sugli sui sul sull sulla sulle sullo suo suoi ti tra tu tua tue tuo tuoi tutti tutto un una uno vi voi vostra vostre vostri vostro è".split(" ")),e.Pipeline.registerFunction(e.it.stopWordFilter,"stopWordFilter-it")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ja.min.js b/assets/javascripts/lunr/min/lunr.ja.min.js new file mode 100644 index 0000000..5f254eb --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ja.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=C.limit)break;C.cursor++;continue}break}for(C.cursor=o,C.bra=o,C.eq_s(1,"y")?(C.ket=C.cursor,C.slice_from("Y")):C.cursor=o;;)if(e=C.cursor,C.in_grouping(q,97,232)){if(i=C.cursor,C.bra=i,C.eq_s(1,"i"))C.ket=C.cursor,C.in_grouping(q,97,232)&&(C.slice_from("I"),C.cursor=e);else if(C.cursor=i,C.eq_s(1,"y"))C.ket=C.cursor,C.slice_from("Y"),C.cursor=e;else if(n(e))break}else if(n(e))break}function n(r){return C.cursor=r,r>=C.limit||(C.cursor++,!1)}function o(){_=C.limit,d=_,t()||(_=C.cursor,_<3&&(_=3),t()||(d=C.cursor))}function t(){for(;!C.in_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}for(;!C.out_grouping(q,97,232);){if(C.cursor>=C.limit)return!0;C.cursor++}return!1}function s(){for(var r;;)if(C.bra=C.cursor,r=C.find_among(p,3))switch(C.ket=C.cursor,r){case 1:C.slice_from("y");break;case 2:C.slice_from("i");break;case 3:if(C.cursor>=C.limit)return;C.cursor++}}function u(){return _<=C.cursor}function c(){return d<=C.cursor}function a(){var r=C.limit-C.cursor;C.find_among_b(g,3)&&(C.cursor=C.limit-r,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del()))}function l(){var r;w=!1,C.ket=C.cursor,C.eq_s_b(1,"e")&&(C.bra=C.cursor,u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.slice_del(),w=!0,a())))}function m(){var r;u()&&(r=C.limit-C.cursor,C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-r,C.eq_s_b(3,"gem")||(C.cursor=C.limit-r,C.slice_del(),a())))}function f(){var r,e,i,n,o,t,s=C.limit-C.cursor;if(C.ket=C.cursor,r=C.find_among_b(h,5))switch(C.bra=C.cursor,r){case 1:u()&&C.slice_from("heid");break;case 2:m();break;case 3:u()&&C.out_grouping_b(j,97,232)&&C.slice_del()}if(C.cursor=C.limit-s,l(),C.cursor=C.limit-s,C.ket=C.cursor,C.eq_s_b(4,"heid")&&(C.bra=C.cursor,c()&&(e=C.limit-C.cursor,C.eq_s_b(1,"c")||(C.cursor=C.limit-e,C.slice_del(),C.ket=C.cursor,C.eq_s_b(2,"en")&&(C.bra=C.cursor,m())))),C.cursor=C.limit-s,C.ket=C.cursor,r=C.find_among_b(k,6))switch(C.bra=C.cursor,r){case 1:if(c()){if(C.slice_del(),i=C.limit-C.cursor,C.ket=C.cursor,C.eq_s_b(2,"ig")&&(C.bra=C.cursor,c()&&(n=C.limit-C.cursor,!C.eq_s_b(1,"e")))){C.cursor=C.limit-n,C.slice_del();break}C.cursor=C.limit-i,a()}break;case 2:c()&&(o=C.limit-C.cursor,C.eq_s_b(1,"e")||(C.cursor=C.limit-o,C.slice_del()));break;case 3:c()&&(C.slice_del(),l());break;case 4:c()&&C.slice_del();break;case 5:c()&&w&&C.slice_del()}C.cursor=C.limit-s,C.out_grouping_b(z,73,232)&&(t=C.limit-C.cursor,C.find_among_b(v,4)&&C.out_grouping_b(q,97,232)&&(C.cursor=C.limit-t,C.ket=C.cursor,C.cursor>C.limit_backward&&(C.cursor--,C.bra=C.cursor,C.slice_del())))}var d,_,w,b=[new e("",-1,6),new e("á",0,1),new e("ä",0,1),new e("é",0,2),new e("ë",0,2),new e("í",0,3),new e("ï",0,3),new e("ó",0,4),new e("ö",0,4),new e("ú",0,5),new e("ü",0,5)],p=[new e("",-1,3),new e("I",0,2),new e("Y",0,1)],g=[new e("dd",-1,-1),new e("kk",-1,-1),new e("tt",-1,-1)],h=[new e("ene",-1,2),new e("se",-1,3),new e("en",-1,2),new e("heden",2,1),new e("s",-1,3)],k=[new e("end",-1,1),new e("ig",-1,2),new e("ing",-1,1),new e("lijk",-1,3),new e("baar",-1,4),new e("bar",-1,5)],v=[new e("aa",-1,-1),new e("ee",-1,-1),new e("oo",-1,-1),new e("uu",-1,-1)],q=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],z=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],j=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],C=new i;this.setCurrent=function(r){C.setCurrent(r)},this.getCurrent=function(){return C.getCurrent()},this.stem=function(){var e=C.cursor;return r(),C.cursor=e,o(),C.limit_backward=e,C.cursor=C.limit,f(),C.cursor=C.limit_backward,s(),!0}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.no.min.js b/assets/javascripts/lunr/min/lunr.no.min.js new file mode 100644 index 0000000..92bc7e4 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.no.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Norwegian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.pt.min.js b/assets/javascripts/lunr/min/lunr.pt.min.js new file mode 100644 index 0000000..6c16996 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.pt.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Portuguese` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=function(){var r=e.stemmerSupport.Among,s=e.stemmerSupport.SnowballProgram,n=new function(){function e(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(k,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("a~");continue;case 2:z.slice_from("o~");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function n(){if(z.out_grouping(y,97,250)){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!0;z.cursor++}return!1}return!0}function i(){if(z.in_grouping(y,97,250))for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return g=z.cursor,!0}function o(){var e,r,s=z.cursor;if(z.in_grouping(y,97,250))if(e=z.cursor,n()){if(z.cursor=e,i())return}else g=z.cursor;if(z.cursor=s,z.out_grouping(y,97,250)){if(r=z.cursor,n()){if(z.cursor=r,!z.in_grouping(y,97,250)||z.cursor>=z.limit)return;z.cursor++}g=z.cursor}}function t(){for(;!z.in_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}for(;!z.out_grouping(y,97,250);){if(z.cursor>=z.limit)return!1;z.cursor++}return!0}function a(){var e=z.cursor;g=z.limit,b=g,h=g,o(),z.cursor=e,t()&&(b=z.cursor,t()&&(h=z.cursor))}function u(){for(var e;;){if(z.bra=z.cursor,e=z.find_among(q,3))switch(z.ket=z.cursor,e){case 1:z.slice_from("ã");continue;case 2:z.slice_from("õ");continue;case 3:if(z.cursor>=z.limit)break;z.cursor++;continue}break}}function w(){return g<=z.cursor}function m(){return b<=z.cursor}function c(){return h<=z.cursor}function l(){var e;if(z.ket=z.cursor,!(e=z.find_among_b(F,45)))return!1;switch(z.bra=z.cursor,e){case 1:if(!c())return!1;z.slice_del();break;case 2:if(!c())return!1;z.slice_from("log");break;case 3:if(!c())return!1;z.slice_from("u");break;case 4:if(!c())return!1;z.slice_from("ente");break;case 5:if(!m())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(j,4),e&&(z.bra=z.cursor,c()&&(z.slice_del(),1==e&&(z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del()))));break;case 6:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(C,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 7:if(!c())return!1;z.slice_del(),z.ket=z.cursor,e=z.find_among_b(P,3),e&&(z.bra=z.cursor,1==e&&c()&&z.slice_del());break;case 8:if(!c())return!1;z.slice_del(),z.ket=z.cursor,z.eq_s_b(2,"at")&&(z.bra=z.cursor,c()&&z.slice_del());break;case 9:if(!w()||!z.eq_s_b(1,"e"))return!1;z.slice_from("ir")}return!0}function f(){var e,r;if(z.cursor>=g){if(r=z.limit_backward,z.limit_backward=g,z.ket=z.cursor,e=z.find_among_b(S,120))return z.bra=z.cursor,1==e&&z.slice_del(),z.limit_backward=r,!0;z.limit_backward=r}return!1}function d(){var e;z.ket=z.cursor,(e=z.find_among_b(W,7))&&(z.bra=z.cursor,1==e&&w()&&z.slice_del())}function v(e,r){if(z.eq_s_b(1,e)){z.bra=z.cursor;var s=z.limit-z.cursor;if(z.eq_s_b(1,r))return z.cursor=z.limit-s,w()&&z.slice_del(),!1}return!0}function p(){var e;if(z.ket=z.cursor,e=z.find_among_b(L,4))switch(z.bra=z.cursor,e){case 1:w()&&(z.slice_del(),z.ket=z.cursor,z.limit-z.cursor,v("u","g")&&v("i","c"));break;case 2:z.slice_from("c")}}function _(){if(!l()&&(z.cursor=z.limit,!f()))return z.cursor=z.limit,void d();z.cursor=z.limit,z.ket=z.cursor,z.eq_s_b(1,"i")&&(z.bra=z.cursor,z.eq_s_b(1,"c")&&(z.cursor=z.limit,w()&&z.slice_del()))}var h,b,g,k=[new r("",-1,3),new r("ã",0,1),new r("õ",0,2)],q=[new r("",-1,3),new r("a~",0,1),new r("o~",0,2)],j=[new r("ic",-1,-1),new r("ad",-1,-1),new r("os",-1,-1),new r("iv",-1,1)],C=[new r("ante",-1,1),new r("avel",-1,1),new r("ível",-1,1)],P=[new r("ic",-1,1),new r("abil",-1,1),new r("iv",-1,1)],F=[new r("ica",-1,1),new r("ância",-1,1),new r("ência",-1,4),new r("ira",-1,9),new r("adora",-1,1),new r("osa",-1,1),new r("ista",-1,1),new r("iva",-1,8),new r("eza",-1,1),new r("logía",-1,2),new r("idade",-1,7),new r("ante",-1,1),new r("mente",-1,6),new r("amente",12,5),new r("ável",-1,1),new r("ível",-1,1),new r("ución",-1,3),new r("ico",-1,1),new r("ismo",-1,1),new r("oso",-1,1),new r("amento",-1,1),new r("imento",-1,1),new r("ivo",-1,8),new r("aça~o",-1,1),new r("ador",-1,1),new r("icas",-1,1),new r("ências",-1,4),new r("iras",-1,9),new r("adoras",-1,1),new r("osas",-1,1),new r("istas",-1,1),new r("ivas",-1,8),new r("ezas",-1,1),new r("logías",-1,2),new r("idades",-1,7),new r("uciones",-1,3),new r("adores",-1,1),new r("antes",-1,1),new r("aço~es",-1,1),new r("icos",-1,1),new r("ismos",-1,1),new r("osos",-1,1),new r("amentos",-1,1),new r("imentos",-1,1),new r("ivos",-1,8)],S=[new r("ada",-1,1),new r("ida",-1,1),new r("ia",-1,1),new r("aria",2,1),new r("eria",2,1),new r("iria",2,1),new r("ara",-1,1),new r("era",-1,1),new r("ira",-1,1),new r("ava",-1,1),new r("asse",-1,1),new r("esse",-1,1),new r("isse",-1,1),new r("aste",-1,1),new r("este",-1,1),new r("iste",-1,1),new r("ei",-1,1),new r("arei",16,1),new r("erei",16,1),new r("irei",16,1),new r("am",-1,1),new r("iam",20,1),new r("ariam",21,1),new r("eriam",21,1),new r("iriam",21,1),new r("aram",20,1),new r("eram",20,1),new r("iram",20,1),new r("avam",20,1),new r("em",-1,1),new r("arem",29,1),new r("erem",29,1),new r("irem",29,1),new r("assem",29,1),new r("essem",29,1),new r("issem",29,1),new r("ado",-1,1),new r("ido",-1,1),new r("ando",-1,1),new r("endo",-1,1),new r("indo",-1,1),new r("ara~o",-1,1),new r("era~o",-1,1),new r("ira~o",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("ir",-1,1),new r("as",-1,1),new r("adas",47,1),new r("idas",47,1),new r("ias",47,1),new r("arias",50,1),new r("erias",50,1),new r("irias",50,1),new r("aras",47,1),new r("eras",47,1),new r("iras",47,1),new r("avas",47,1),new r("es",-1,1),new r("ardes",58,1),new r("erdes",58,1),new r("irdes",58,1),new r("ares",58,1),new r("eres",58,1),new r("ires",58,1),new r("asses",58,1),new r("esses",58,1),new r("isses",58,1),new r("astes",58,1),new r("estes",58,1),new r("istes",58,1),new r("is",-1,1),new r("ais",71,1),new r("eis",71,1),new r("areis",73,1),new r("ereis",73,1),new r("ireis",73,1),new r("áreis",73,1),new r("éreis",73,1),new r("íreis",73,1),new r("ásseis",73,1),new r("ésseis",73,1),new r("ísseis",73,1),new r("áveis",73,1),new r("íeis",73,1),new r("aríeis",84,1),new r("eríeis",84,1),new r("iríeis",84,1),new r("ados",-1,1),new r("idos",-1,1),new r("amos",-1,1),new r("áramos",90,1),new r("éramos",90,1),new r("íramos",90,1),new r("ávamos",90,1),new r("íamos",90,1),new r("aríamos",95,1),new r("eríamos",95,1),new r("iríamos",95,1),new r("emos",-1,1),new r("aremos",99,1),new r("eremos",99,1),new r("iremos",99,1),new r("ássemos",99,1),new r("êssemos",99,1),new r("íssemos",99,1),new r("imos",-1,1),new r("armos",-1,1),new r("ermos",-1,1),new r("irmos",-1,1),new r("ámos",-1,1),new r("arás",-1,1),new r("erás",-1,1),new r("irás",-1,1),new r("eu",-1,1),new r("iu",-1,1),new r("ou",-1,1),new r("ará",-1,1),new r("erá",-1,1),new r("irá",-1,1)],W=[new r("a",-1,1),new r("i",-1,1),new r("o",-1,1),new r("os",-1,1),new r("á",-1,1),new r("í",-1,1),new r("ó",-1,1)],L=[new r("e",-1,1),new r("ç",-1,2),new r("é",-1,1),new r("ê",-1,1)],y=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],z=new s;this.setCurrent=function(e){z.setCurrent(e)},this.getCurrent=function(){return z.getCurrent()},this.stem=function(){var r=z.cursor;return e(),z.cursor=r,a(),z.limit_backward=r,z.cursor=z.limit,_(),z.cursor=z.limit,p(),z.cursor=z.limit_backward,u(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ro.min.js b/assets/javascripts/lunr/min/lunr.ro.min.js new file mode 100644 index 0000000..7277140 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ro.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Romanian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ro=function(){this.pipeline.reset(),this.pipeline.add(e.ro.trimmer,e.ro.stopWordFilter,e.ro.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ro.stemmer))},e.ro.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.ro.trimmer=e.trimmerSupport.generateTrimmer(e.ro.wordCharacters),e.Pipeline.registerFunction(e.ro.trimmer,"trimmer-ro"),e.ro.stemmer=function(){var i=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,n=new function(){function e(e,i){L.eq_s(1,e)&&(L.ket=L.cursor,L.in_grouping(W,97,259)&&L.slice_from(i))}function n(){for(var i,r;;){if(i=L.cursor,L.in_grouping(W,97,259)&&(r=L.cursor,L.bra=r,e("u","U"),L.cursor=r,e("i","I")),L.cursor=i,L.cursor>=L.limit)break;L.cursor++}}function t(){if(L.out_grouping(W,97,259)){for(;!L.in_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}return!0}function a(){if(L.in_grouping(W,97,259))for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!0;L.cursor++}return!1}function o(){var e,i,r=L.cursor;if(L.in_grouping(W,97,259)){if(e=L.cursor,!t())return void(h=L.cursor);if(L.cursor=e,!a())return void(h=L.cursor)}L.cursor=r,L.out_grouping(W,97,259)&&(i=L.cursor,t()&&(L.cursor=i,L.in_grouping(W,97,259)&&L.cursor=L.limit)return!1;L.cursor++}for(;!L.out_grouping(W,97,259);){if(L.cursor>=L.limit)return!1;L.cursor++}return!0}function c(){var e=L.cursor;h=L.limit,k=h,g=h,o(),L.cursor=e,u()&&(k=L.cursor,u()&&(g=L.cursor))}function s(){for(var e;;){if(L.bra=L.cursor,e=L.find_among(z,3))switch(L.ket=L.cursor,e){case 1:L.slice_from("i");continue;case 2:L.slice_from("u");continue;case 3:if(L.cursor>=L.limit)break;L.cursor++;continue}break}}function w(){return h<=L.cursor}function m(){return k<=L.cursor}function l(){return g<=L.cursor}function f(){var e,i;if(L.ket=L.cursor,(e=L.find_among_b(C,16))&&(L.bra=L.cursor,m()))switch(e){case 1:L.slice_del();break;case 2:L.slice_from("a");break;case 3:L.slice_from("e");break;case 4:L.slice_from("i");break;case 5:i=L.limit-L.cursor,L.eq_s_b(2,"ab")||(L.cursor=L.limit-i,L.slice_from("i"));break;case 6:L.slice_from("at");break;case 7:L.slice_from("aţi")}}function p(){var e,i=L.limit-L.cursor;if(L.ket=L.cursor,(e=L.find_among_b(P,46))&&(L.bra=L.cursor,m())){switch(e){case 1:L.slice_from("abil");break;case 2:L.slice_from("ibil");break;case 3:L.slice_from("iv");break;case 4:L.slice_from("ic");break;case 5:L.slice_from("at");break;case 6:L.slice_from("it")}return _=!0,L.cursor=L.limit-i,!0}return!1}function d(){var e,i;for(_=!1;;)if(i=L.limit-L.cursor,!p()){L.cursor=L.limit-i;break}if(L.ket=L.cursor,(e=L.find_among_b(F,62))&&(L.bra=L.cursor,l())){switch(e){case 1:L.slice_del();break;case 2:L.eq_s_b(1,"ţ")&&(L.bra=L.cursor,L.slice_from("t"));break;case 3:L.slice_from("ist")}_=!0}}function b(){var e,i,r;if(L.cursor>=h){if(i=L.limit_backward,L.limit_backward=h,L.ket=L.cursor,e=L.find_among_b(q,94))switch(L.bra=L.cursor,e){case 1:if(r=L.limit-L.cursor,!L.out_grouping_b(W,97,259)&&(L.cursor=L.limit-r,!L.eq_s_b(1,"u")))break;case 2:L.slice_del()}L.limit_backward=i}}function v(){var e;L.ket=L.cursor,(e=L.find_among_b(S,5))&&(L.bra=L.cursor,w()&&1==e&&L.slice_del())}var _,g,k,h,z=[new i("",-1,3),new i("I",0,1),new i("U",0,2)],C=[new i("ea",-1,3),new i("aţia",-1,7),new i("aua",-1,2),new i("iua",-1,4),new i("aţie",-1,7),new i("ele",-1,3),new i("ile",-1,5),new i("iile",6,4),new i("iei",-1,4),new i("atei",-1,6),new i("ii",-1,4),new i("ului",-1,1),new i("ul",-1,1),new i("elor",-1,3),new i("ilor",-1,4),new i("iilor",14,4)],P=[new i("icala",-1,4),new i("iciva",-1,4),new i("ativa",-1,5),new i("itiva",-1,6),new i("icale",-1,4),new i("aţiune",-1,5),new i("iţiune",-1,6),new i("atoare",-1,5),new i("itoare",-1,6),new i("ătoare",-1,5),new i("icitate",-1,4),new i("abilitate",-1,1),new i("ibilitate",-1,2),new i("ivitate",-1,3),new i("icive",-1,4),new i("ative",-1,5),new i("itive",-1,6),new i("icali",-1,4),new i("atori",-1,5),new i("icatori",18,4),new i("itori",-1,6),new i("ători",-1,5),new i("icitati",-1,4),new i("abilitati",-1,1),new i("ivitati",-1,3),new i("icivi",-1,4),new i("ativi",-1,5),new i("itivi",-1,6),new i("icităi",-1,4),new i("abilităi",-1,1),new i("ivităi",-1,3),new i("icităţi",-1,4),new i("abilităţi",-1,1),new i("ivităţi",-1,3),new i("ical",-1,4),new i("ator",-1,5),new i("icator",35,4),new i("itor",-1,6),new i("ător",-1,5),new i("iciv",-1,4),new i("ativ",-1,5),new i("itiv",-1,6),new i("icală",-1,4),new i("icivă",-1,4),new i("ativă",-1,5),new i("itivă",-1,6)],F=[new i("ica",-1,1),new i("abila",-1,1),new i("ibila",-1,1),new i("oasa",-1,1),new i("ata",-1,1),new i("ita",-1,1),new i("anta",-1,1),new i("ista",-1,3),new i("uta",-1,1),new i("iva",-1,1),new i("ic",-1,1),new i("ice",-1,1),new i("abile",-1,1),new i("ibile",-1,1),new i("isme",-1,3),new i("iune",-1,2),new i("oase",-1,1),new i("ate",-1,1),new i("itate",17,1),new i("ite",-1,1),new i("ante",-1,1),new i("iste",-1,3),new i("ute",-1,1),new i("ive",-1,1),new i("ici",-1,1),new i("abili",-1,1),new i("ibili",-1,1),new i("iuni",-1,2),new i("atori",-1,1),new i("osi",-1,1),new i("ati",-1,1),new i("itati",30,1),new i("iti",-1,1),new i("anti",-1,1),new i("isti",-1,3),new i("uti",-1,1),new i("işti",-1,3),new i("ivi",-1,1),new i("ităi",-1,1),new i("oşi",-1,1),new i("ităţi",-1,1),new i("abil",-1,1),new i("ibil",-1,1),new i("ism",-1,3),new i("ator",-1,1),new i("os",-1,1),new i("at",-1,1),new i("it",-1,1),new i("ant",-1,1),new i("ist",-1,3),new i("ut",-1,1),new i("iv",-1,1),new i("ică",-1,1),new i("abilă",-1,1),new i("ibilă",-1,1),new i("oasă",-1,1),new i("ată",-1,1),new i("ită",-1,1),new i("antă",-1,1),new i("istă",-1,3),new i("ută",-1,1),new i("ivă",-1,1)],q=[new i("ea",-1,1),new i("ia",-1,1),new i("esc",-1,1),new i("ăsc",-1,1),new i("ind",-1,1),new i("ând",-1,1),new i("are",-1,1),new i("ere",-1,1),new i("ire",-1,1),new i("âre",-1,1),new i("se",-1,2),new i("ase",10,1),new i("sese",10,2),new i("ise",10,1),new i("use",10,1),new i("âse",10,1),new i("eşte",-1,1),new i("ăşte",-1,1),new i("eze",-1,1),new i("ai",-1,1),new i("eai",19,1),new i("iai",19,1),new i("sei",-1,2),new i("eşti",-1,1),new i("ăşti",-1,1),new i("ui",-1,1),new i("ezi",-1,1),new i("âi",-1,1),new i("aşi",-1,1),new i("seşi",-1,2),new i("aseşi",29,1),new i("seseşi",29,2),new i("iseşi",29,1),new i("useşi",29,1),new i("âseşi",29,1),new i("işi",-1,1),new i("uşi",-1,1),new i("âşi",-1,1),new i("aţi",-1,2),new i("eaţi",38,1),new i("iaţi",38,1),new i("eţi",-1,2),new i("iţi",-1,2),new i("âţi",-1,2),new i("arăţi",-1,1),new i("serăţi",-1,2),new i("aserăţi",45,1),new i("seserăţi",45,2),new i("iserăţi",45,1),new i("userăţi",45,1),new i("âserăţi",45,1),new i("irăţi",-1,1),new i("urăţi",-1,1),new i("ârăţi",-1,1),new i("am",-1,1),new i("eam",54,1),new i("iam",54,1),new i("em",-1,2),new i("asem",57,1),new i("sesem",57,2),new i("isem",57,1),new i("usem",57,1),new i("âsem",57,1),new i("im",-1,2),new i("âm",-1,2),new i("ăm",-1,2),new i("arăm",65,1),new i("serăm",65,2),new i("aserăm",67,1),new i("seserăm",67,2),new i("iserăm",67,1),new i("userăm",67,1),new i("âserăm",67,1),new i("irăm",65,1),new i("urăm",65,1),new i("ârăm",65,1),new i("au",-1,1),new i("eau",76,1),new i("iau",76,1),new i("indu",-1,1),new i("ându",-1,1),new i("ez",-1,1),new i("ească",-1,1),new i("ară",-1,1),new i("seră",-1,2),new i("aseră",84,1),new i("seseră",84,2),new i("iseră",84,1),new i("useră",84,1),new i("âseră",84,1),new i("iră",-1,1),new i("ură",-1,1),new i("âră",-1,1),new i("ează",-1,1)],S=[new i("a",-1,1),new i("e",-1,1),new i("ie",1,1),new i("i",-1,1),new i("ă",-1,1)],W=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,32,0,0,4],L=new r;this.setCurrent=function(e){L.setCurrent(e)},this.getCurrent=function(){return L.getCurrent()},this.stem=function(){var e=L.cursor;return n(),L.cursor=e,c(),L.limit_backward=e,L.cursor=L.limit,f(),L.cursor=L.limit,d(),L.cursor=L.limit,_||(L.cursor=L.limit,b(),L.cursor=L.limit),v(),L.cursor=L.limit_backward,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.ro.stemmer,"stemmer-ro"),e.ro.stopWordFilter=e.generateStopWordFilter("acea aceasta această aceea acei aceia acel acela acele acelea acest acesta aceste acestea aceşti aceştia acolo acord acum ai aia aibă aici al ale alea altceva altcineva am ar are asemenea asta astea astăzi asupra au avea avem aveţi azi aş aşadar aţi bine bucur bună ca care caut ce cel ceva chiar cinci cine cineva contra cu cum cumva curând curînd când cât câte câtva câţi cînd cît cîte cîtva cîţi că căci cărei căror cărui către da dacă dar datorită dată dau de deci deja deoarece departe deşi din dinaintea dintr- dintre doi doilea două drept după dă ea ei el ele eram este eu eşti face fata fi fie fiecare fii fim fiu fiţi frumos fără graţie halbă iar ieri la le li lor lui lângă lîngă mai mea mei mele mereu meu mi mie mine mult multă mulţi mulţumesc mâine mîine mă ne nevoie nici nicăieri nimeni nimeri nimic nişte noastre noastră noi noroc nostru nouă noştri nu opt ori oricare orice oricine oricum oricând oricât oricînd oricît oriunde patra patru patrulea pe pentru peste pic poate pot prea prima primul prin puţin puţina puţină până pînă rog sa sale sau se spate spre sub sunt suntem sunteţi sută sînt sîntem sînteţi să săi său ta tale te timp tine toate toată tot totuşi toţi trei treia treilea tu tăi tău un una unde undeva unei uneia unele uneori unii unor unora unu unui unuia unul vi voastre voastră voi vostru vouă voştri vreme vreo vreun vă zece zero zi zice îi îl îmi împotriva în înainte înaintea încotro încât încît între întrucât întrucît îţi ăla ălea ăsta ăstea ăştia şapte şase şi ştiu ţi ţie".split(" ")),e.Pipeline.registerFunction(e.ro.stopWordFilter,"stopWordFilter-ro")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.ru.min.js b/assets/javascripts/lunr/min/lunr.ru.min.js new file mode 100644 index 0000000..186cc48 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.ru.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Russian` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=function(){var n=e.stemmerSupport.Among,r=e.stemmerSupport.SnowballProgram,t=new function(){function e(){for(;!W.in_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function t(){for(;!W.out_grouping(S,1072,1103);){if(W.cursor>=W.limit)return!1;W.cursor++}return!0}function w(){b=W.limit,_=b,e()&&(b=W.cursor,t()&&e()&&t()&&(_=W.cursor))}function i(){return _<=W.cursor}function u(e,n){var r,t;if(W.ket=W.cursor,r=W.find_among_b(e,n)){switch(W.bra=W.cursor,r){case 1:if(t=W.limit-W.cursor,!W.eq_s_b(1,"а")&&(W.cursor=W.limit-t,!W.eq_s_b(1,"я")))return!1;case 2:W.slice_del()}return!0}return!1}function o(){return u(h,9)}function s(e,n){var r;return W.ket=W.cursor,!!(r=W.find_among_b(e,n))&&(W.bra=W.cursor,1==r&&W.slice_del(),!0)}function c(){return s(g,26)}function m(){return!!c()&&(u(C,8),!0)}function f(){return s(k,2)}function l(){return u(P,46)}function a(){s(v,36)}function p(){var e;W.ket=W.cursor,(e=W.find_among_b(F,2))&&(W.bra=W.cursor,i()&&1==e&&W.slice_del())}function d(){var e;if(W.ket=W.cursor,e=W.find_among_b(q,4))switch(W.bra=W.cursor,e){case 1:if(W.slice_del(),W.ket=W.cursor,!W.eq_s_b(1,"н"))break;W.bra=W.cursor;case 2:if(!W.eq_s_b(1,"н"))break;case 3:W.slice_del()}}var _,b,h=[new n("в",-1,1),new n("ив",0,2),new n("ыв",0,2),new n("вши",-1,1),new n("ивши",3,2),new n("ывши",3,2),new n("вшись",-1,1),new n("ившись",6,2),new n("ывшись",6,2)],g=[new n("ее",-1,1),new n("ие",-1,1),new n("ое",-1,1),new n("ые",-1,1),new n("ими",-1,1),new n("ыми",-1,1),new n("ей",-1,1),new n("ий",-1,1),new n("ой",-1,1),new n("ый",-1,1),new n("ем",-1,1),new n("им",-1,1),new n("ом",-1,1),new n("ым",-1,1),new n("его",-1,1),new n("ого",-1,1),new n("ему",-1,1),new n("ому",-1,1),new n("их",-1,1),new n("ых",-1,1),new n("ею",-1,1),new n("ою",-1,1),new n("ую",-1,1),new n("юю",-1,1),new n("ая",-1,1),new n("яя",-1,1)],C=[new n("ем",-1,1),new n("нн",-1,1),new n("вш",-1,1),new n("ивш",2,2),new n("ывш",2,2),new n("щ",-1,1),new n("ющ",5,1),new n("ующ",6,2)],k=[new n("сь",-1,1),new n("ся",-1,1)],P=[new n("ла",-1,1),new n("ила",0,2),new n("ыла",0,2),new n("на",-1,1),new n("ена",3,2),new n("ете",-1,1),new n("ите",-1,2),new n("йте",-1,1),new n("ейте",7,2),new n("уйте",7,2),new n("ли",-1,1),new n("или",10,2),new n("ыли",10,2),new n("й",-1,1),new n("ей",13,2),new n("уй",13,2),new n("л",-1,1),new n("ил",16,2),new n("ыл",16,2),new n("ем",-1,1),new n("им",-1,2),new n("ым",-1,2),new n("н",-1,1),new n("ен",22,2),new n("ло",-1,1),new n("ило",24,2),new n("ыло",24,2),new n("но",-1,1),new n("ено",27,2),new n("нно",27,1),new n("ет",-1,1),new n("ует",30,2),new n("ит",-1,2),new n("ыт",-1,2),new n("ют",-1,1),new n("уют",34,2),new n("ят",-1,2),new n("ны",-1,1),new n("ены",37,2),new n("ть",-1,1),new n("ить",39,2),new n("ыть",39,2),new n("ешь",-1,1),new n("ишь",-1,2),new n("ю",-1,2),new n("ую",44,2)],v=[new n("а",-1,1),new n("ев",-1,1),new n("ов",-1,1),new n("е",-1,1),new n("ие",3,1),new n("ье",3,1),new n("и",-1,1),new n("еи",6,1),new n("ии",6,1),new n("ами",6,1),new n("ями",6,1),new n("иями",10,1),new n("й",-1,1),new n("ей",12,1),new n("ией",13,1),new n("ий",12,1),new n("ой",12,1),new n("ам",-1,1),new n("ем",-1,1),new n("ием",18,1),new n("ом",-1,1),new n("ям",-1,1),new n("иям",21,1),new n("о",-1,1),new n("у",-1,1),new n("ах",-1,1),new n("ях",-1,1),new n("иях",26,1),new n("ы",-1,1),new n("ь",-1,1),new n("ю",-1,1),new n("ию",30,1),new n("ью",30,1),new n("я",-1,1),new n("ия",33,1),new n("ья",33,1)],F=[new n("ост",-1,1),new n("ость",-1,1)],q=[new n("ейше",-1,1),new n("н",-1,2),new n("ейш",-1,1),new n("ь",-1,3)],S=[33,65,8,232],W=new r;this.setCurrent=function(e){W.setCurrent(e)},this.getCurrent=function(){return W.getCurrent()},this.stem=function(){return w(),W.cursor=W.limit,!(W.cursor=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.sv.min.js b/assets/javascripts/lunr/min/lunr.sv.min.js new file mode 100644 index 0000000..3e5eb64 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.sv.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Swedish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.th.min.js b/assets/javascripts/lunr/min/lunr.th.min.js new file mode 100644 index 0000000..dee3aac --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.th.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.tr.min.js b/assets/javascripts/lunr/min/lunr.tr.min.js new file mode 100644 index 0000000..563f6ec --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.tr.min.js @@ -0,0 +1,18 @@ +/*! + * Lunr languages, `Turkish` language + * https://github.com/MihaiValentin/lunr-languages + * + * Copyright 2014, Mihai Valentin + * http://www.mozilla.org/MPL/ + */ +/*! + * based on + * Snowball JavaScript Library v0.3 + * http://code.google.com/p/urim/ + * http://snowball.tartarus.org/ + * + * Copyright 2010, Oleg Mazko + * http://www.mozilla.org/MPL/ + */ + +!function(r,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(r.lunr)}(this,function(){return function(r){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");r.tr=function(){this.pipeline.reset(),this.pipeline.add(r.tr.trimmer,r.tr.stopWordFilter,r.tr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(r.tr.stemmer))},r.tr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",r.tr.trimmer=r.trimmerSupport.generateTrimmer(r.tr.wordCharacters),r.Pipeline.registerFunction(r.tr.trimmer,"trimmer-tr"),r.tr.stemmer=function(){var i=r.stemmerSupport.Among,e=r.stemmerSupport.SnowballProgram,n=new function(){function r(r,i,e){for(;;){var n=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(r,i,e)){Dr.cursor=Dr.limit-n;break}if(Dr.cursor=Dr.limit-n,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function n(){var i,e;i=Dr.limit-Dr.cursor,r(Wr,97,305);for(var n=0;nDr.limit_backward&&(Dr.cursor--,e=Dr.limit-Dr.cursor,i()))?(Dr.cursor=Dr.limit-e,!0):(Dr.cursor=Dr.limit-n,r()?(Dr.cursor=Dr.limit-n,!1):(Dr.cursor=Dr.limit-n,!(Dr.cursor<=Dr.limit_backward)&&(Dr.cursor--,!!i()&&(Dr.cursor=Dr.limit-n,!0))))}function u(r){return t(r,function(){return Dr.in_grouping_b(Wr,97,305)})}function o(){return u(function(){return Dr.eq_s_b(1,"n")})}function s(){return u(function(){return Dr.eq_s_b(1,"s")})}function c(){return u(function(){return Dr.eq_s_b(1,"y")})}function l(){return t(function(){return Dr.in_grouping_b(Lr,105,305)},function(){return Dr.out_grouping_b(Wr,97,305)})}function a(){return Dr.find_among_b(ur,10)&&l()}function m(){return n()&&Dr.in_grouping_b(Lr,105,305)&&s()}function d(){return Dr.find_among_b(or,2)}function f(){return n()&&Dr.in_grouping_b(Lr,105,305)&&c()}function b(){return n()&&Dr.find_among_b(sr,4)}function w(){return n()&&Dr.find_among_b(cr,4)&&o()}function _(){return n()&&Dr.find_among_b(lr,2)&&c()}function k(){return n()&&Dr.find_among_b(ar,2)}function p(){return n()&&Dr.find_among_b(mr,4)}function g(){return n()&&Dr.find_among_b(dr,2)}function y(){return n()&&Dr.find_among_b(fr,4)}function z(){return n()&&Dr.find_among_b(br,2)}function v(){return n()&&Dr.find_among_b(wr,2)&&c()}function h(){return Dr.eq_s_b(2,"ki")}function q(){return n()&&Dr.find_among_b(_r,2)&&o()}function C(){return n()&&Dr.find_among_b(kr,4)&&c()}function P(){return n()&&Dr.find_among_b(pr,4)}function F(){return n()&&Dr.find_among_b(gr,4)&&c()}function S(){return Dr.find_among_b(yr,4)}function W(){return n()&&Dr.find_among_b(zr,2)}function L(){return n()&&Dr.find_among_b(vr,4)}function x(){return n()&&Dr.find_among_b(hr,8)}function A(){return Dr.find_among_b(qr,2)}function E(){return n()&&Dr.find_among_b(Cr,32)&&c()}function j(){return Dr.find_among_b(Pr,8)&&c()}function T(){return n()&&Dr.find_among_b(Fr,4)&&c()}function Z(){return Dr.eq_s_b(3,"ken")&&c()}function B(){var r=Dr.limit-Dr.cursor;return!(T()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,Z()))))}function D(){if(A()){var r=Dr.limit-Dr.cursor;if(S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T())return!1}return!0}function G(){if(W()){Dr.bra=Dr.cursor,Dr.slice_del();var r=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,x()||(Dr.cursor=Dr.limit-r,E()||(Dr.cursor=Dr.limit-r,j()||(Dr.cursor=Dr.limit-r,T()||(Dr.cursor=Dr.limit-r)))),nr=!1,!1}return!0}function H(){if(!L())return!0;var r=Dr.limit-Dr.cursor;return!E()&&(Dr.cursor=Dr.limit-r,!j())}function I(){var r,i=Dr.limit-Dr.cursor;return!(S()||(Dr.cursor=Dr.limit-i,F()||(Dr.cursor=Dr.limit-i,P()||(Dr.cursor=Dr.limit-i,C()))))||(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,T()||(Dr.cursor=Dr.limit-r),!1)}function J(){var r,i=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,nr=!0,B()&&(Dr.cursor=Dr.limit-i,D()&&(Dr.cursor=Dr.limit-i,G()&&(Dr.cursor=Dr.limit-i,H()&&(Dr.cursor=Dr.limit-i,I()))))){if(Dr.cursor=Dr.limit-i,!x())return;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,S()||(Dr.cursor=Dr.limit-r,W()||(Dr.cursor=Dr.limit-r,C()||(Dr.cursor=Dr.limit-r,P()||(Dr.cursor=Dr.limit-r,F()||(Dr.cursor=Dr.limit-r))))),T()||(Dr.cursor=Dr.limit-r)}Dr.bra=Dr.cursor,Dr.slice_del()}function K(){var r,i,e,n;if(Dr.ket=Dr.cursor,h()){if(r=Dr.limit-Dr.cursor,p())return Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,a()&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))),!0;if(Dr.cursor=Dr.limit-r,w()){if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,e=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-e,!m()&&(Dr.cursor=Dr.limit-e,!K())))return!0;Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}return!0}if(Dr.cursor=Dr.limit-r,g()){if(n=Dr.limit-Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-n,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-n,!K())return!1;return!0}}return!1}function M(r){if(Dr.ket=Dr.cursor,!g()&&(Dr.cursor=Dr.limit-r,!k()))return!1;var i=Dr.limit-Dr.cursor;if(d())Dr.bra=Dr.cursor,Dr.slice_del();else if(Dr.cursor=Dr.limit-i,m())Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K());else if(Dr.cursor=Dr.limit-i,!K())return!1;return!0}function N(r){if(Dr.ket=Dr.cursor,!z()&&(Dr.cursor=Dr.limit-r,!b()))return!1;var i=Dr.limit-Dr.cursor;return!(!m()&&(Dr.cursor=Dr.limit-i,!d()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)}function O(){var r,i=Dr.limit-Dr.cursor;return Dr.ket=Dr.cursor,!(!w()&&(Dr.cursor=Dr.limit-i,!v()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,!(!W()||(Dr.bra=Dr.cursor,Dr.slice_del(),!K()))||(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!(a()||(Dr.cursor=Dr.limit-r,m()||(Dr.cursor=Dr.limit-r,K())))||(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()),!0)))}function Q(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,!p()&&(Dr.cursor=Dr.limit-e,!f()&&(Dr.cursor=Dr.limit-e,!_())))return!1;if(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,r=Dr.limit-Dr.cursor,a())Dr.bra=Dr.cursor,Dr.slice_del(),i=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,W()||(Dr.cursor=Dr.limit-i);else if(Dr.cursor=Dr.limit-r,!W())return!0;return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,K(),!0}function R(){var r,i,e=Dr.limit-Dr.cursor;if(Dr.ket=Dr.cursor,W())return Dr.bra=Dr.cursor,Dr.slice_del(),void K();if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,q())if(Dr.bra=Dr.cursor,Dr.slice_del(),r=Dr.limit-Dr.cursor,Dr.ket=Dr.cursor,d())Dr.bra=Dr.cursor,Dr.slice_del();else{if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!a()&&(Dr.cursor=Dr.limit-r,!m())){if(Dr.cursor=Dr.limit-r,Dr.ket=Dr.cursor,!W())return;if(Dr.bra=Dr.cursor,Dr.slice_del(),!K())return}Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())}else if(Dr.cursor=Dr.limit-e,!M(e)&&(Dr.cursor=Dr.limit-e,!N(e))){if(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,y())return Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,i=Dr.limit-Dr.cursor,void(a()?(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K())):(Dr.cursor=Dr.limit-i,W()?(Dr.bra=Dr.cursor,Dr.slice_del(),K()):(Dr.cursor=Dr.limit-i,K())));if(Dr.cursor=Dr.limit-e,!O()){if(Dr.cursor=Dr.limit-e,d())return Dr.bra=Dr.cursor,void Dr.slice_del();Dr.cursor=Dr.limit-e,K()||(Dr.cursor=Dr.limit-e,Q()||(Dr.cursor=Dr.limit-e,Dr.ket=Dr.cursor,(a()||(Dr.cursor=Dr.limit-e,m()))&&(Dr.bra=Dr.cursor,Dr.slice_del(),Dr.ket=Dr.cursor,W()&&(Dr.bra=Dr.cursor,Dr.slice_del(),K()))))}}}function U(){var r;if(Dr.ket=Dr.cursor,r=Dr.find_among_b(Sr,4))switch(Dr.bra=Dr.cursor,r){case 1:Dr.slice_from("p");break;case 2:Dr.slice_from("ç");break;case 3:Dr.slice_from("t");break;case 4:Dr.slice_from("k")}}function V(){for(;;){var r=Dr.limit-Dr.cursor;if(Dr.in_grouping_b(Wr,97,305)){Dr.cursor=Dr.limit-r;break}if(Dr.cursor=Dr.limit-r,Dr.cursor<=Dr.limit_backward)return!1;Dr.cursor--}return!0}function X(r,i,e){if(Dr.cursor=Dr.limit-r,V()){var n=Dr.limit-Dr.cursor;if(!Dr.eq_s_b(1,i)&&(Dr.cursor=Dr.limit-n,!Dr.eq_s_b(1,e)))return!0;Dr.cursor=Dr.limit-r;var t=Dr.cursor;return Dr.insert(Dr.cursor,Dr.cursor,e),Dr.cursor=t,!1}return!0}function Y(){var r=Dr.limit-Dr.cursor;(Dr.eq_s_b(1,"d")||(Dr.cursor=Dr.limit-r,Dr.eq_s_b(1,"g")))&&X(r,"a","ı")&&X(r,"e","i")&&X(r,"o","u")&&X(r,"ö","ü")}function $(){for(var r,i=Dr.cursor,e=2;;){for(r=Dr.cursor;!Dr.in_grouping(Wr,97,305);){if(Dr.cursor>=Dr.limit)return Dr.cursor=r,!(e>0)&&(Dr.cursor=i,!0);Dr.cursor++}e--}}function rr(r,i,e){for(;!Dr.eq_s(i,e);){if(Dr.cursor>=Dr.limit)return!0;Dr.cursor++}return(tr=i)!=Dr.limit||(Dr.cursor=r,!1)}function ir(){var r=Dr.cursor;return!rr(r,2,"ad")||(Dr.cursor=r,!rr(r,5,"soyad"))}function er(){var r=Dr.cursor;return!ir()&&(Dr.limit_backward=r,Dr.cursor=Dr.limit,Y(),Dr.cursor=Dr.limit,U(),!0)}var nr,tr,ur=[new i("m",-1,-1),new i("n",-1,-1),new i("miz",-1,-1),new i("niz",-1,-1),new i("muz",-1,-1),new i("nuz",-1,-1),new i("müz",-1,-1),new i("nüz",-1,-1),new i("mız",-1,-1),new i("nız",-1,-1)],or=[new i("leri",-1,-1),new i("ları",-1,-1)],sr=[new i("ni",-1,-1),new i("nu",-1,-1),new i("nü",-1,-1),new i("nı",-1,-1)],cr=[new i("in",-1,-1),new i("un",-1,-1),new i("ün",-1,-1),new i("ın",-1,-1)],lr=[new i("a",-1,-1),new i("e",-1,-1)],ar=[new i("na",-1,-1),new i("ne",-1,-1)],mr=[new i("da",-1,-1),new i("ta",-1,-1),new i("de",-1,-1),new i("te",-1,-1)],dr=[new i("nda",-1,-1),new i("nde",-1,-1)],fr=[new i("dan",-1,-1),new i("tan",-1,-1),new i("den",-1,-1),new i("ten",-1,-1)],br=[new i("ndan",-1,-1),new i("nden",-1,-1)],wr=[new i("la",-1,-1),new i("le",-1,-1)],_r=[new i("ca",-1,-1),new i("ce",-1,-1)],kr=[new i("im",-1,-1),new i("um",-1,-1),new i("üm",-1,-1),new i("ım",-1,-1)],pr=[new i("sin",-1,-1),new i("sun",-1,-1),new i("sün",-1,-1),new i("sın",-1,-1)],gr=[new i("iz",-1,-1),new i("uz",-1,-1),new i("üz",-1,-1),new i("ız",-1,-1)],yr=[new i("siniz",-1,-1),new i("sunuz",-1,-1),new i("sünüz",-1,-1),new i("sınız",-1,-1)],zr=[new i("lar",-1,-1),new i("ler",-1,-1)],vr=[new i("niz",-1,-1),new i("nuz",-1,-1),new i("nüz",-1,-1),new i("nız",-1,-1)],hr=[new i("dir",-1,-1),new i("tir",-1,-1),new i("dur",-1,-1),new i("tur",-1,-1),new i("dür",-1,-1),new i("tür",-1,-1),new i("dır",-1,-1),new i("tır",-1,-1)],qr=[new i("casına",-1,-1),new i("cesine",-1,-1)],Cr=[new i("di",-1,-1),new i("ti",-1,-1),new i("dik",-1,-1),new i("tik",-1,-1),new i("duk",-1,-1),new i("tuk",-1,-1),new i("dük",-1,-1),new i("tük",-1,-1),new i("dık",-1,-1),new i("tık",-1,-1),new i("dim",-1,-1),new i("tim",-1,-1),new i("dum",-1,-1),new i("tum",-1,-1),new i("düm",-1,-1),new i("tüm",-1,-1),new i("dım",-1,-1),new i("tım",-1,-1),new i("din",-1,-1),new i("tin",-1,-1),new i("dun",-1,-1),new i("tun",-1,-1),new i("dün",-1,-1),new i("tün",-1,-1),new i("dın",-1,-1),new i("tın",-1,-1),new i("du",-1,-1),new i("tu",-1,-1),new i("dü",-1,-1),new i("tü",-1,-1),new i("dı",-1,-1),new i("tı",-1,-1)],Pr=[new i("sa",-1,-1),new i("se",-1,-1),new i("sak",-1,-1),new i("sek",-1,-1),new i("sam",-1,-1),new i("sem",-1,-1),new i("san",-1,-1),new i("sen",-1,-1)],Fr=[new i("miş",-1,-1),new i("muş",-1,-1),new i("müş",-1,-1),new i("mış",-1,-1)],Sr=[new i("b",-1,1),new i("c",-1,2),new i("d",-1,3),new i("ğ",-1,4)],Wr=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,8,0,0,0,0,0,0,1],Lr=[1,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,1],xr=[1,64,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],Ar=[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130],Er=[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],jr=[17],Tr=[65],Zr=[65],Br=[["a",xr,97,305],["e",Ar,101,252],["ı",Er,97,305],["i",jr,101,105],["o",Tr,111,117],["ö",Zr,246,252],["u",Tr,111,117]],Dr=new e;this.setCurrent=function(r){Dr.setCurrent(r)},this.getCurrent=function(){return Dr.getCurrent()},this.stem=function(){return!!($()&&(Dr.limit_backward=Dr.cursor,Dr.cursor=Dr.limit,J(),Dr.cursor=Dr.limit,nr&&(R(),Dr.cursor=Dr.limit_backward,er())))}};return function(r){return"function"==typeof r.update?r.update(function(r){return n.setCurrent(r),n.stem(),n.getCurrent()}):(n.setCurrent(r),n.stem(),n.getCurrent())}}(),r.Pipeline.registerFunction(r.tr.stemmer,"stemmer-tr"),r.tr.stopWordFilter=r.generateStopWordFilter("acaba altmış altı ama ancak arada aslında ayrıca bana bazı belki ben benden beni benim beri beş bile bin bir biri birkaç birkez birçok birşey birşeyi biz bizden bize bizi bizim bu buna bunda bundan bunlar bunları bunların bunu bunun burada böyle böylece da daha dahi de defa değil diye diğer doksan dokuz dolayı dolayısıyla dört edecek eden ederek edilecek ediliyor edilmesi ediyor elli en etmesi etti ettiği ettiğini eğer gibi göre halen hangi hatta hem henüz hep hepsi her herhangi herkesin hiç hiçbir iki ile ilgili ise itibaren itibariyle için işte kadar karşın katrilyon kendi kendilerine kendini kendisi kendisine kendisini kez ki kim kimden kime kimi kimse kırk milyar milyon mu mü mı nasıl ne neden nedenle nerde nerede nereye niye niçin o olan olarak oldu olduklarını olduğu olduğunu olmadı olmadığı olmak olması olmayan olmaz olsa olsun olup olur olursa oluyor on ona ondan onlar onlardan onları onların onu onun otuz oysa pek rağmen sadece sanki sekiz seksen sen senden seni senin siz sizden sizi sizin tarafından trilyon tüm var vardı ve veya ya yani yapacak yapmak yaptı yaptıkları yaptığı yaptığını yapılan yapılması yapıyor yedi yerine yetmiş yine yirmi yoksa yüz zaten çok çünkü öyle üzere üç şey şeyden şeyi şeyler şu şuna şunda şundan şunları şunu şöyle".split(" ")),r.Pipeline.registerFunction(r.tr.stopWordFilter,"stopWordFilter-tr")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.vi.min.js b/assets/javascripts/lunr/min/lunr.vi.min.js new file mode 100644 index 0000000..22aed28 --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.vi.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/min/lunr.zh.min.js b/assets/javascripts/lunr/min/lunr.zh.min.js new file mode 100644 index 0000000..7727bbe --- /dev/null +++ b/assets/javascripts/lunr/min/lunr.zh.min.js @@ -0,0 +1 @@ +!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("nodejieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 以 于 上 他 而 后 之 来 及 了 因 下 可 到 由 这 与 也 此 但 并 个 其 已 无 小 我 们 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 从 到 得 打 凡 儿 尔 该 各 给 跟 和 何 还 即 几 既 看 据 距 靠 啦 了 另 么 每 们 嘛 拿 哪 那 您 凭 且 却 让 仍 啥 如 若 使 谁 虽 随 同 所 她 哇 嗡 往 哪 些 向 沿 哟 用 于 咱 则 怎 曾 至 致 着 诸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); \ No newline at end of file diff --git a/assets/javascripts/lunr/tinyseg.js b/assets/javascripts/lunr/tinyseg.js new file mode 100644 index 0000000..167fa6d --- /dev/null +++ b/assets/javascripts/lunr/tinyseg.js @@ -0,0 +1,206 @@ +/** + * export the module via AMD, CommonJS or as a browser global + * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js + */ +;(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(factory) + } else if (typeof exports === 'object') { + /** + * Node. Does not work with strict CommonJS, but + * only CommonJS-like environments that support module.exports, + * like Node. + */ + module.exports = factory() + } else { + // Browser globals (root is window) + factory()(root.lunr); + } +}(this, function () { + /** + * Just return a value to define the module export. + * This example returns an object, but the module + * can return a function as the exported value. + */ + + return function(lunr) { + // TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript + // (c) 2008 Taku Kudo + // TinySegmenter is freely distributable under the terms of a new BSD licence. + // For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt + + function TinySegmenter() { + var patterns = { + "[一二三四五六七八九十百千万億兆]":"M", + "[一-龠々〆ヵヶ]":"H", + "[ぁ-ん]":"I", + "[ァ-ヴーア-ン゙ー]":"K", + "[a-zA-Za-zA-Z]":"A", + "[0-90-9]":"N" + } + this.chartype_ = []; + for (var i in patterns) { + var regexp = new RegExp(i); + this.chartype_.push([regexp, patterns[i]]); + } + + this.BIAS__ = -332 + this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378}; + this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920}; + this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266}; + this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352}; + this.BP2__ = {"BO":60,"OO":-1762}; + this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965}; + this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146}; + this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699}; + this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973}; + this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682}; + this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669}; + this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990}; + this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832}; + this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649}; + this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393}; + this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841}; + this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68}; + this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591}; + this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685}; + this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156}; + this.TW1__ = {"につい":-4681,"東京都":2026}; + this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216}; + this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287}; + this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865}; + this.UC1__ = {"A":484,"K":93,"M":645,"O":-505}; + this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646}; + this.UC3__ = {"A":-1370,"I":2311}; + this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646}; + this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831}; + this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387}; + this.UP1__ = {"O":-214}; + this.UP2__ = {"B":69,"O":935}; + this.UP3__ = {"B":189}; + this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422}; + this.UQ2__ = {"BH":216,"BI":113,"OK":1759}; + this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212}; + this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135}; + this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568}; + this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278}; + this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637}; + this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343}; + this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496}; + + return this; + } + TinySegmenter.prototype.ctype_ = function(str) { + for (var i in this.chartype_) { + if (str.match(this.chartype_[i][0])) { + return this.chartype_[i][1]; + } + } + return "O"; + } + + TinySegmenter.prototype.ts_ = function(v) { + if (v) { return v; } + return 0; + } + + TinySegmenter.prototype.segment = function(input) { + if (input == null || input == undefined || input == "") { + return []; + } + var result = []; + var seg = ["B3","B2","B1"]; + var ctype = ["O","O","O"]; + var o = input.split(""); + for (i = 0; i < o.length; ++i) { + seg.push(o[i]); + ctype.push(this.ctype_(o[i])) + } + seg.push("E1"); + seg.push("E2"); + seg.push("E3"); + ctype.push("O"); + ctype.push("O"); + ctype.push("O"); + var word = seg[3]; + var p1 = "U"; + var p2 = "U"; + var p3 = "U"; + for (var i = 4; i < seg.length - 3; ++i) { + var score = this.BIAS__; + var w1 = seg[i-3]; + var w2 = seg[i-2]; + var w3 = seg[i-1]; + var w4 = seg[i]; + var w5 = seg[i+1]; + var w6 = seg[i+2]; + var c1 = ctype[i-3]; + var c2 = ctype[i-2]; + var c3 = ctype[i-1]; + var c4 = ctype[i]; + var c5 = ctype[i+1]; + var c6 = ctype[i+2]; + score += this.ts_(this.UP1__[p1]); + score += this.ts_(this.UP2__[p2]); + score += this.ts_(this.UP3__[p3]); + score += this.ts_(this.BP1__[p1 + p2]); + score += this.ts_(this.BP2__[p2 + p3]); + score += this.ts_(this.UW1__[w1]); + score += this.ts_(this.UW2__[w2]); + score += this.ts_(this.UW3__[w3]); + score += this.ts_(this.UW4__[w4]); + score += this.ts_(this.UW5__[w5]); + score += this.ts_(this.UW6__[w6]); + score += this.ts_(this.BW1__[w2 + w3]); + score += this.ts_(this.BW2__[w3 + w4]); + score += this.ts_(this.BW3__[w4 + w5]); + score += this.ts_(this.TW1__[w1 + w2 + w3]); + score += this.ts_(this.TW2__[w2 + w3 + w4]); + score += this.ts_(this.TW3__[w3 + w4 + w5]); + score += this.ts_(this.TW4__[w4 + w5 + w6]); + score += this.ts_(this.UC1__[c1]); + score += this.ts_(this.UC2__[c2]); + score += this.ts_(this.UC3__[c3]); + score += this.ts_(this.UC4__[c4]); + score += this.ts_(this.UC5__[c5]); + score += this.ts_(this.UC6__[c6]); + score += this.ts_(this.BC1__[c2 + c3]); + score += this.ts_(this.BC2__[c3 + c4]); + score += this.ts_(this.BC3__[c4 + c5]); + score += this.ts_(this.TC1__[c1 + c2 + c3]); + score += this.ts_(this.TC2__[c2 + c3 + c4]); + score += this.ts_(this.TC3__[c3 + c4 + c5]); + score += this.ts_(this.TC4__[c4 + c5 + c6]); + // score += this.ts_(this.TC5__[c4 + c5 + c6]); + score += this.ts_(this.UQ1__[p1 + c1]); + score += this.ts_(this.UQ2__[p2 + c2]); + score += this.ts_(this.UQ3__[p3 + c3]); + score += this.ts_(this.BQ1__[p2 + c2 + c3]); + score += this.ts_(this.BQ2__[p2 + c3 + c4]); + score += this.ts_(this.BQ3__[p3 + c2 + c3]); + score += this.ts_(this.BQ4__[p3 + c3 + c4]); + score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]); + score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]); + score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]); + score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]); + var p = "O"; + if (score > 0) { + result.push(word); + word = ""; + p = "B"; + } + p1 = p2; + p2 = p3; + p3 = p; + word += seg[i]; + } + result.push(word); + + return result; + } + + lunr.TinySegmenter = TinySegmenter; + }; + +})); \ No newline at end of file diff --git a/assets/javascripts/lunr/wordcut.js b/assets/javascripts/lunr/wordcut.js new file mode 100644 index 0000000..146f4b4 --- /dev/null +++ b/assets/javascripts/lunr/wordcut.js @@ -0,0 +1,6708 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.lunr || (g.lunr = {})).wordcut = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1; + }) + this.addWords(words, false) + } + if(finalize){ + this.finalizeDict(); + } + }, + + dictSeek: function (l, r, ch, strOffset, pos) { + var ans = null; + while (l <= r) { + var m = Math.floor((l + r) / 2), + dict_item = this.dict[m], + len = dict_item.length; + if (len <= strOffset) { + l = m + 1; + } else { + var ch_ = dict_item[strOffset]; + if (ch_ < ch) { + l = m + 1; + } else if (ch_ > ch) { + r = m - 1; + } else { + ans = m; + if (pos == LEFT) { + r = m - 1; + } else { + l = m + 1; + } + } + } + } + return ans; + }, + + isFinal: function (acceptor) { + return this.dict[acceptor.l].length == acceptor.strOffset; + }, + + createAcceptor: function () { + return { + l: 0, + r: this.dict.length - 1, + strOffset: 0, + isFinal: false, + dict: this, + transit: function (ch) { + return this.dict.transit(this, ch); + }, + isError: false, + tag: "DICT", + w: 1, + type: "DICT" + }; + }, + + transit: function (acceptor, ch) { + var l = this.dictSeek(acceptor.l, + acceptor.r, + ch, + acceptor.strOffset, + LEFT); + if (l !== null) { + var r = this.dictSeek(l, + acceptor.r, + ch, + acceptor.strOffset, + RIGHT); + acceptor.l = l; + acceptor.r = r; + acceptor.strOffset++; + acceptor.isFinal = this.isFinal(acceptor); + } else { + acceptor.isError = true; + } + return acceptor; + }, + + sortuniq: function(a){ + return a.sort().filter(function(item, pos, arr){ + return !pos || item != arr[pos - 1]; + }) + }, + + flatten: function(a){ + //[[1,2],[3]] -> [1,2,3] + return [].concat.apply([], a); + } +}; +module.exports = WordcutDict; + +}).call(this,"/dist/tmp") +},{"glob":16,"path":22}],3:[function(require,module,exports){ +var WordRule = { + createAcceptor: function(tag) { + if (tag["WORD_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + var lch = ch.toLowerCase(); + if (lch >= "a" && lch <= "z") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "WORD_RULE", + type: "WORD_RULE", + w: 1}; + } +}; + +var NumberRule = { + createAcceptor: function(tag) { + if (tag["NUMBER_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch >= "0" && ch <= "9") { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "NUMBER_RULE", + type: "NUMBER_RULE", + w: 1}; + } +}; + +var SpaceRule = { + tag: "SPACE_RULE", + createAcceptor: function(tag) { + + if (tag["SPACE_RULE"]) + return null; + + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (ch == " " || ch == "\t" || ch == "\r" || ch == "\n" || + ch == "\u00A0" || ch=="\u2003"//nbsp and emsp + ) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: SpaceRule.tag, + w: 1, + type: "SPACE_RULE"}; + } +} + +var SingleSymbolRule = { + tag: "SINSYM", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (this.strOffset == 0 && ch.match(/^[\@\(\)\/\,\-\."`]$/)) { + this.isFinal = true; + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "SINSYM", + w: 1, + type: "SINSYM"}; + } +} + + +var LatinRules = [WordRule, SpaceRule, SingleSymbolRule, NumberRule]; + +module.exports = LatinRules; + +},{}],4:[function(require,module,exports){ +var _ = require("underscore") + , WordcutCore = require("./wordcut_core"); +var PathInfoBuilder = { + + /* + buildByPartAcceptors: function(path, acceptors, i) { + var + var genInfos = partAcceptors.reduce(function(genInfos, acceptor) { + + }, []); + + return genInfos; + } + */ + + buildByAcceptors: function(path, finalAcceptors, i) { + var self = this; + var infos = finalAcceptors.map(function(acceptor) { + var p = i - acceptor.strOffset + 1 + , _info = path[p]; + + var info = {p: p, + mw: _info.mw + (acceptor.mw === undefined ? 0 : acceptor.mw), + w: acceptor.w + _info.w, + unk: (acceptor.unk ? acceptor.unk : 0) + _info.unk, + type: acceptor.type}; + + if (acceptor.type == "PART") { + for(var j = p + 1; j <= i; j++) { + path[j].merge = p; + } + info.merge = p; + } + + return info; + }); + return infos.filter(function(info) { return info; }); + }, + + fallback: function(path, leftBoundary, text, i) { + var _info = path[leftBoundary]; + if (text[i].match(/[\u0E48-\u0E4E]/)) { + if (leftBoundary != 0) + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + mw: 0, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; +/* } else if(leftBoundary > 0 && path[leftBoundary].type !== "UNK") { + leftBoundary = path[leftBoundary].p; + return {p: leftBoundary, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; */ + } else { + return {p: leftBoundary, + mw: _info.mw, + w: 1 + _info.w, + unk: 1 + _info.unk, + type: "UNK"}; + } + }, + + build: function(path, finalAcceptors, i, leftBoundary, text) { + var basicPathInfos = this.buildByAcceptors(path, finalAcceptors, i); + if (basicPathInfos.length > 0) { + return basicPathInfos; + } else { + return [this.fallback(path, leftBoundary, text, i)]; + } + } +}; + +module.exports = function() { + return _.clone(PathInfoBuilder); +} + +},{"./wordcut_core":8,"underscore":25}],5:[function(require,module,exports){ +var _ = require("underscore"); + + +var PathSelector = { + selectPath: function(paths) { + var path = paths.reduce(function(selectedPath, path) { + if (selectedPath == null) { + return path; + } else { + if (path.unk < selectedPath.unk) + return path; + if (path.unk == selectedPath.unk) { + if (path.mw < selectedPath.mw) + return path + if (path.mw == selectedPath.mw) { + if (path.w < selectedPath.w) + return path; + } + } + return selectedPath; + } + }, null); + return path; + }, + + createPath: function() { + return [{p:null, w:0, unk:0, type: "INIT", mw:0}]; + } +}; + +module.exports = function() { + return _.clone(PathSelector); +}; + +},{"underscore":25}],6:[function(require,module,exports){ +function isMatch(pat, offset, ch) { + if (pat.length <= offset) + return false; + var _ch = pat[offset]; + return _ch == ch || + (_ch.match(/[กข]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/[มบ]/) && ch.match(/[ก-ฮ]/)) || + (_ch.match(/\u0E49/) && ch.match(/[\u0E48-\u0E4B]/)); +} + +var Rule0 = { + pat: "เหก็ม", + createAcceptor: function(tag) { + return {strOffset: 0, + isFinal: false, + transit: function(ch) { + if (isMatch(Rule0.pat, this.strOffset,ch)) { + this.isFinal = (this.strOffset + 1 == Rule0.pat.length); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "THAI_RULE", + type: "THAI_RULE", + w: 1}; + } +}; + +var PartRule = { + createAcceptor: function(tag) { + return {strOffset: 0, + patterns: [ + "แก", "เก", "ก้", "กก์", "กา", "กี", "กิ", "กืก" + ], + isFinal: false, + transit: function(ch) { + var offset = this.strOffset; + this.patterns = this.patterns.filter(function(pat) { + return isMatch(pat, offset, ch); + }); + + if (this.patterns.length > 0) { + var len = 1 + offset; + this.isFinal = this.patterns.some(function(pat) { + return pat.length == len; + }); + this.strOffset++; + } else { + this.isError = true; + } + return this; + }, + isError: false, + tag: "PART", + type: "PART", + unk: 1, + w: 1}; + } +}; + +var ThaiRules = [Rule0, PartRule]; + +module.exports = ThaiRules; + +},{}],7:[function(require,module,exports){ +var sys = require("sys") + , WordcutDict = require("./dict") + , WordcutCore = require("./wordcut_core") + , PathInfoBuilder = require("./path_info_builder") + , PathSelector = require("./path_selector") + , Acceptors = require("./acceptors") + , latinRules = require("./latin_rules") + , thaiRules = require("./thai_rules") + , _ = require("underscore"); + + +var Wordcut = Object.create(WordcutCore); +Wordcut.defaultPathInfoBuilder = PathInfoBuilder; +Wordcut.defaultPathSelector = PathSelector; +Wordcut.defaultAcceptors = Acceptors; +Wordcut.defaultLatinRules = latinRules; +Wordcut.defaultThaiRules = thaiRules; +Wordcut.defaultDict = WordcutDict; + + +Wordcut.initNoDict = function(dict_path) { + var self = this; + self.pathInfoBuilder = new self.defaultPathInfoBuilder; + self.pathSelector = new self.defaultPathSelector; + self.acceptors = new self.defaultAcceptors; + self.defaultLatinRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); + self.defaultThaiRules.forEach(function(rule) { + self.acceptors.creators.push(rule); + }); +}; + +Wordcut.init = function(dict_path, withDefault, additionalWords) { + withDefault = withDefault || false; + this.initNoDict(); + var dict = _.clone(this.defaultDict); + dict.init(dict_path, withDefault, additionalWords); + this.acceptors.creators.push(dict); +}; + +module.exports = Wordcut; + +},{"./acceptors":1,"./dict":2,"./latin_rules":3,"./path_info_builder":4,"./path_selector":5,"./thai_rules":6,"./wordcut_core":8,"sys":28,"underscore":25}],8:[function(require,module,exports){ +var WordcutCore = { + + buildPath: function(text) { + var self = this + , path = self.pathSelector.createPath() + , leftBoundary = 0; + self.acceptors.reset(); + for (var i = 0; i < text.length; i++) { + var ch = text[i]; + self.acceptors.transit(ch); + + var possiblePathInfos = self + .pathInfoBuilder + .build(path, + self.acceptors.getFinalAcceptors(), + i, + leftBoundary, + text); + var selectedPath = self.pathSelector.selectPath(possiblePathInfos) + + path.push(selectedPath); + if (selectedPath.type !== "UNK") { + leftBoundary = i; + } + } + return path; + }, + + pathToRanges: function(path) { + var e = path.length - 1 + , ranges = []; + + while (e > 0) { + var info = path[e] + , s = info.p; + + if (info.merge !== undefined && ranges.length > 0) { + var r = ranges[ranges.length - 1]; + r.s = info.merge; + s = r.s; + } else { + ranges.push({s:s, e:e}); + } + e = s; + } + return ranges.reverse(); + }, + + rangesToText: function(text, ranges, delimiter) { + return ranges.map(function(r) { + return text.substring(r.s, r.e); + }).join(delimiter); + }, + + cut: function(text, delimiter) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + return this + .rangesToText(text, ranges, + (delimiter === undefined ? "|" : delimiter)); + }, + + cutIntoRanges: function(text, noText) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + if (!noText) { + ranges.forEach(function(r) { + r.text = text.substring(r.s, r.e); + }); + } + return ranges; + }, + + cutIntoArray: function(text) { + var path = this.buildPath(text) + , ranges = this.pathToRanges(path); + + return ranges.map(function(r) { + return text.substring(r.s, r.e) + }); + } +}; + +module.exports = WordcutCore; + +},{}],9:[function(require,module,exports){ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Originally from narwhal.js (http://narwhaljs.org) +// Copyright (c) 2009 Thomas Robinson <280north.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the 'Software'), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// when used in node, this will actually load the util module we depend on +// versus loading the builtin util module as happens otherwise +// this is a bug in node module loading as far as I am concerned +var util = require('util/'); + +var pSlice = Array.prototype.slice; +var hasOwn = Object.prototype.hasOwnProperty; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } + else { + // non v8 browsers so we can have a stacktrace + var err = new Error(); + if (err.stack) { + var out = err.stack; + + // try to strip useless frames + var fn_name = stackStartFunction.name; + var idx = out.indexOf('\n' + fn_name); + if (idx >= 0) { + // once we have located the function frame + // we need to strip out everything before it (and its line) + var next_line = out.indexOf('\n', idx + 1); + out = out.substring(next_line + 1); + } + + this.stack = out; + } + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && !isFinite(value)) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + // if one is a primitive, the other must be same + if (util.isPrimitive(a) || util.isPrimitive(b)) { + return a === b; + } + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + var ka = objectKeys(a), + kb = objectKeys(b), + key, i; + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + if (hasOwn.call(obj, key)) keys.push(key); + } + return keys; +}; + +},{"util/":28}],10:[function(require,module,exports){ +'use strict'; +module.exports = balanced; +function balanced(a, b, str) { + if (a instanceof RegExp) a = maybeMatch(a, str); + if (b instanceof RegExp) b = maybeMatch(b, str); + + var r = range(a, b, str); + + return r && { + start: r[0], + end: r[1], + pre: str.slice(0, r[0]), + body: str.slice(r[0] + a.length, r[1]), + post: str.slice(r[1] + b.length) + }; +} + +function maybeMatch(reg, str) { + var m = str.match(reg); + return m ? m[0] : null; +} + +balanced.range = range; +function range(a, b, str) { + var begs, beg, left, right, result; + var ai = str.indexOf(a); + var bi = str.indexOf(b, ai + 1); + var i = ai; + + if (ai >= 0 && bi > 0) { + begs = []; + left = str.length; + + while (i >= 0 && !result) { + if (i == ai) { + begs.push(i); + ai = str.indexOf(a, i + 1); + } else if (begs.length == 1) { + result = [ begs.pop(), bi ]; + } else { + beg = begs.pop(); + if (beg < left) { + left = beg; + right = bi; + } + + bi = str.indexOf(b, i + 1); + } + + i = ai < bi && ai >= 0 ? ai : bi; + } + + if (begs.length) { + result = [ left, right ]; + } + } + + return result; +} + +},{}],11:[function(require,module,exports){ +var concatMap = require('concat-map'); +var balanced = require('balanced-match'); + +module.exports = expandTop; + +var escSlash = '\0SLASH'+Math.random()+'\0'; +var escOpen = '\0OPEN'+Math.random()+'\0'; +var escClose = '\0CLOSE'+Math.random()+'\0'; +var escComma = '\0COMMA'+Math.random()+'\0'; +var escPeriod = '\0PERIOD'+Math.random()+'\0'; + +function numeric(str) { + return parseInt(str, 10) == str + ? parseInt(str, 10) + : str.charCodeAt(0); +} + +function escapeBraces(str) { + return str.split('\\\\').join(escSlash) + .split('\\{').join(escOpen) + .split('\\}').join(escClose) + .split('\\,').join(escComma) + .split('\\.').join(escPeriod); +} + +function unescapeBraces(str) { + return str.split(escSlash).join('\\') + .split(escOpen).join('{') + .split(escClose).join('}') + .split(escComma).join(',') + .split(escPeriod).join('.'); +} + + +// Basically just str.split(","), but handling cases +// where we have nested braced sections, which should be +// treated as individual members, like {a,{b,c},d} +function parseCommaParts(str) { + if (!str) + return ['']; + + var parts = []; + var m = balanced('{', '}', str); + + if (!m) + return str.split(','); + + var pre = m.pre; + var body = m.body; + var post = m.post; + var p = pre.split(','); + + p[p.length-1] += '{' + body + '}'; + var postParts = parseCommaParts(post); + if (post.length) { + p[p.length-1] += postParts.shift(); + p.push.apply(p, postParts); + } + + parts.push.apply(parts, p); + + return parts; +} + +function expandTop(str) { + if (!str) + return []; + + // I don't know why Bash 4.3 does this, but it does. + // Anything starting with {} will have the first two bytes preserved + // but *only* at the top level, so {},a}b will not expand to anything, + // but a{},b}c will be expanded to [a}c,abc]. + // One could argue that this is a bug in Bash, but since the goal of + // this module is to match Bash's rules, we escape a leading {} + if (str.substr(0, 2) === '{}') { + str = '\\{\\}' + str.substr(2); + } + + return expand(escapeBraces(str), true).map(unescapeBraces); +} + +function identity(e) { + return e; +} + +function embrace(str) { + return '{' + str + '}'; +} +function isPadded(el) { + return /^-?0\d/.test(el); +} + +function lte(i, y) { + return i <= y; +} +function gte(i, y) { + return i >= y; +} + +function expand(str, isTop) { + var expansions = []; + + var m = balanced('{', '}', str); + if (!m || /\$$/.test(m.pre)) return [str]; + + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); + var isSequence = isNumericSequence || isAlphaSequence; + var isOptions = m.body.indexOf(',') >= 0; + if (!isSequence && !isOptions) { + // {a},b} + if (m.post.match(/,.*\}/)) { + str = m.pre + '{' + m.body + escClose + m.post; + return expand(str); + } + return [str]; + } + + var n; + if (isSequence) { + n = m.body.split(/\.\./); + } else { + n = parseCommaParts(m.body); + if (n.length === 1) { + // x{{a,b}}y ==> x{a}y x{b}y + n = expand(n[0], false).map(embrace); + if (n.length === 1) { + var post = m.post.length + ? expand(m.post, false) + : ['']; + return post.map(function(p) { + return m.pre + n[0] + p; + }); + } + } + } + + // at this point, n is the parts, and we know it's not a comma set + // with a single entry. + + // no need to expand pre, since it is guaranteed to be free of brace-sets + var pre = m.pre; + var post = m.post.length + ? expand(m.post, false) + : ['']; + + var N; + + if (isSequence) { + var x = numeric(n[0]); + var y = numeric(n[1]); + var width = Math.max(n[0].length, n[1].length) + var incr = n.length == 3 + ? Math.abs(numeric(n[2])) + : 1; + var test = lte; + var reverse = y < x; + if (reverse) { + incr *= -1; + test = gte; + } + var pad = n.some(isPadded); + + N = []; + + for (var i = x; test(i, y); i += incr) { + var c; + if (isAlphaSequence) { + c = String.fromCharCode(i); + if (c === '\\') + c = ''; + } else { + c = String(i); + if (pad) { + var need = width - c.length; + if (need > 0) { + var z = new Array(need + 1).join('0'); + if (i < 0) + c = '-' + z + c.slice(1); + else + c = z + c; + } + } + } + N.push(c); + } + } else { + N = concatMap(n, function(el) { return expand(el, false) }); + } + + for (var j = 0; j < N.length; j++) { + for (var k = 0; k < post.length; k++) { + var expansion = pre + N[j] + post[k]; + if (!isTop || isSequence || expansion) + expansions.push(expansion); + } + } + + return expansions; +} + + +},{"balanced-match":10,"concat-map":13}],12:[function(require,module,exports){ + +},{}],13:[function(require,module,exports){ +module.exports = function (xs, fn) { + var res = []; + for (var i = 0; i < xs.length; i++) { + var x = fn(xs[i], i); + if (isArray(x)) res.push.apply(res, x); + else res.push(x); + } + return res; +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +},{}],14:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}],15:[function(require,module,exports){ +(function (process){ +exports.alphasort = alphasort +exports.alphasorti = alphasorti +exports.setopts = setopts +exports.ownProp = ownProp +exports.makeAbs = makeAbs +exports.finish = finish +exports.mark = mark +exports.isIgnored = isIgnored +exports.childrenIgnored = childrenIgnored + +function ownProp (obj, field) { + return Object.prototype.hasOwnProperty.call(obj, field) +} + +var path = require("path") +var minimatch = require("minimatch") +var isAbsolute = require("path-is-absolute") +var Minimatch = minimatch.Minimatch + +function alphasorti (a, b) { + return a.toLowerCase().localeCompare(b.toLowerCase()) +} + +function alphasort (a, b) { + return a.localeCompare(b) +} + +function setupIgnores (self, options) { + self.ignore = options.ignore || [] + + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] + + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) + } +} + +function ignoreMap (pattern) { + var gmatcher = null + if (pattern.slice(-3) === '/**') { + var gpattern = pattern.replace(/(\/\*\*)+$/, '') + gmatcher = new Minimatch(gpattern) + } + + return { + matcher: new Minimatch(pattern), + gmatcher: gmatcher + } +} + +function setopts (self, pattern, options) { + if (!options) + options = {} + + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } + + self.silent = !!options.silent + self.pattern = pattern + self.strict = options.strict !== false + self.realpath = !!options.realpath + self.realpathCache = options.realpathCache || Object.create(null) + self.follow = !!options.follow + self.dot = !!options.dot + self.mark = !!options.mark + self.nodir = !!options.nodir + if (self.nodir) + self.mark = true + self.sync = !!options.sync + self.nounique = !!options.nounique + self.nonull = !!options.nonull + self.nosort = !!options.nosort + self.nocase = !!options.nocase + self.stat = !!options.stat + self.noprocess = !!options.noprocess + + self.maxLength = options.maxLength || Infinity + self.cache = options.cache || Object.create(null) + self.statCache = options.statCache || Object.create(null) + self.symlinks = options.symlinks || Object.create(null) + + setupIgnores(self, options) + + self.changedCwd = false + var cwd = process.cwd() + if (!ownProp(options, "cwd")) + self.cwd = cwd + else { + self.cwd = options.cwd + self.changedCwd = path.resolve(options.cwd) !== cwd + } + + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") + + self.nomount = !!options.nomount + + // disable comments and negation unless the user explicitly + // passes in false as the option. + options.nonegate = options.nonegate === false ? false : true + options.nocomment = options.nocomment === false ? false : true + deprecationWarning(options) + + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} + +// TODO(isaacs): remove entirely in v6 +// exported to reset in tests +exports.deprecationWarned +function deprecationWarning(options) { + if (!options.nonegate || !options.nocomment) { + if (process.noDeprecation !== true && !exports.deprecationWarned) { + var msg = 'glob WARNING: comments and negation will be disabled in v6' + if (process.throwDeprecation) + throw new Error(msg) + else if (process.traceDeprecation) + console.trace(msg) + else + console.error(msg) + + exports.deprecationWarned = true + } + } +} + +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) + + for (var i = 0, l = self.matches.length; i < l; i ++) { + var matches = self.matches[i] + if (!matches || Object.keys(matches).length === 0) { + if (self.nonull) { + // do like the shell, and spit out the literal glob + var literal = self.minimatch.globSet[i] + if (nou) + all.push(literal) + else + all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) + all.push.apply(all, m) + else + m.forEach(function (m) { + all[m] = true + }) + } + } + + if (!nou) + all = Object.keys(all) + + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) + + // at *some* point we statted all of these + if (self.mark) { + for (var i = 0; i < all.length; i++) { + all[i] = self._mark(all[i]) + } + if (self.nodir) { + all = all.filter(function (e) { + return !(/\/$/.test(e)) + }) + } + } + + if (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) + + self.found = all +} + +function mark (self, p) { + var abs = makeAbs(self, p) + var c = self.cache[abs] + var m = p + if (c) { + var isDir = c === 'DIR' || Array.isArray(c) + var slash = p.slice(-1) === '/' + + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) + + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] + } + } + + return m +} + +// lotta situps... +function makeAbs (self, f) { + var abs = f + if (f.charAt(0) === '/') { + abs = path.join(self.root, f) + } else if (isAbsolute(f) || f === '') { + abs = f + } else if (self.changedCwd) { + abs = path.resolve(self.cwd, f) + } else { + abs = path.resolve(f) + } + return abs +} + + +// Return true, if pattern ends with globstar '**', for the accompanying parent directory. +// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents +function isIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false + + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) +} + +}).call(this,require('_process')) +},{"_process":24,"minimatch":20,"path":22,"path-is-absolute":23}],16:[function(require,module,exports){ +(function (process){ +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern, false) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern, inGlobStar) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// +// If inGlobStar and PREFIX is symlink and points to dir +// set ENTRIES = [] +// else readdir(PREFIX) as ENTRIES +// If fail, END +// +// with ENTRIES +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// // Mark that this entry is a globstar match +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. + +module.exports = glob + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var inherits = require('inherits') +var EE = require('events').EventEmitter +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var globSync = require('./sync.js') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var inflight = require('inflight') +var util = require('util') +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored + +var once = require('once') + +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} + + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } + + return new Glob(pattern, options, cb) +} + +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync + +// old api surface +glob.glob = glob + +glob.hasMagic = function (pattern, options_) { + var options = util._extend({}, options_) + options.noprocess = true + + var g = new Glob(pattern, options) + var set = g.minimatch.set + if (set.length > 1) + return true + + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } + + return false +} + +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } + + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } + + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) + + setopts(this, pattern, options) + this._didRealPath = false + + // process each pattern in the minimatch set + var n = this.minimatch.set.length + + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) + + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } + + var self = this + var n = this.minimatch.set.length + this._processing = 0 + this.matches = new Array(n) + + this._emitQueue = [] + this._processQueue = [] + this.paused = false + + if (this.noprocess) + return this + + if (n === 0) + return done() + + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) + } + + function done () { + --self._processing + if (self._processing <= 0) + self._finish() + } +} + +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return + + if (this.realpath && !this._didRealpath) + return this._realpath() + + common.finish(this) + this.emit('end', this.found) +} + +Glob.prototype._realpath = function () { + if (this._didRealpath) + return + + this._didRealpath = true + + var n = this.matches.length + if (n === 0) + return this._finish() + + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) + + function next () { + if (--n === 0) + self._finish() + } +} + +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() + + var found = Object.keys(matchset) + var self = this + var n = found.length + + if (n === 0) + return cb() + + var set = this.matches[index] = Object.create(null) + found.forEach(function (p, i) { + // If there's a problem with the stat, then it means that + // one or more of the links in the realpath couldn't be + // resolved. just return the abs value in that case. + p = self._makeAbs(p) + fs.realpath(p, self.realpathCache, function (er, real) { + if (!er) + set[real] = true + else if (er.syscall === 'stat') + set[p] = true + else + self.emit('error', er) // srsly wtf right here + + if (--n === 0) { + self.matches[index] = set + cb() + } + }) + }) +} + +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} + +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} + +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} + +Glob.prototype.resume = function () { + if (this.paused) { + this.emit('resume') + this.paused = false + if (this._emitQueue.length) { + var eq = this._emitQueue.slice(0) + this._emitQueue.length = 0 + for (var i = 0; i < eq.length; i ++) { + var e = eq[i] + this._emitMatch(e[0], e[1]) + } + } + if (this._processQueue.length) { + var pq = this._processQueue.slice(0) + this._processQueue.length = 0 + for (var i = 0; i < pq.length; i ++) { + var p = pq[i] + this._processing-- + this._process(p[0], p[1], p[2], p[3]) + } + } + } +} + +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') + + if (this.aborted) + return + + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return + } + + //console.error('PROCESS %d', this._processing, pattern) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index, cb) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) +} + +Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return cb() + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this._emitMatch(index, e) + } + // This was the last one, and no stats were needed + return cb() + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + this._process([e].concat(remain), index, inGlobStar, cb) + } + cb() +} + +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return + + if (this.matches[index][e]) + return + + if (isIgnored(this, e)) + return + + if (this.paused) { + this._emitQueue.push([index, e]) + return + } + + var abs = this._makeAbs(e) + + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } + + if (this.mark) + e = this._mark(e) + + this.matches[index][e] = true + + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) + + this.emit('match', e) +} + +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return + + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) + + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) + + if (lstatcb) + fs.lstat(abs, lstatcb) + + function lstatcb_ (er, lstat) { + if (er) + return cb() + + var isSym = lstat.isSymbolicLink() + self.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) { + self.cache[abs] = 'FILE' + cb() + } else + self._readdir(abs, false, cb) + } +} + +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return + + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return + + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() + + if (Array.isArray(c)) + return cb(null, c) + } + + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} + +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) + } +} + +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return + + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + return cb(null, entries) +} + +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return + + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) { + this.emit('error', er) + // If the error is handled, then we abort + // if not, we threw out of here + this.abort() + } + if (!this.silent) + console.error('glob error', er) + break + } + + return cb() +} + +Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { + var self = this + this._readdir(abs, inGlobStar, function (er, entries) { + self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) + }) +} + + +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) + + var isSym = this.symlinks[abs] + var len = entries.length + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, cb) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true, cb) + } + + cb() +} + +Glob.prototype._processSimple = function (prefix, index, cb) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var self = this + this._stat(prefix, function (er, exists) { + self._processSimple2(prefix, index, er, exists, cb) + }) +} +Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { + + //console.error('ps2', prefix, exists) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return cb() + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} + +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return cb() + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) + + if (needDir && c === 'FILE') + return cb() + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (stat !== undefined) { + if (stat === false) + return cb(null, stat) + else { + var type = stat.isDirectory() ? 'DIR' : 'FILE' + if (needDir && type === 'FILE') + return cb() + else + return cb(null, type, stat) + } + } + + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) + + function lstatcb_ (er, lstat) { + if (lstat && lstat.isSymbolicLink()) { + // If it's a symlink, then treat it as the target, unless + // the target does not exist, then treat it as a file. + return fs.stat(abs, function (er, stat) { + if (er) + self._stat2(f, abs, null, lstat, cb) + else + self._stat2(f, abs, er, stat, cb) + }) + } else { + self._stat2(f, abs, er, lstat, cb) + } + } +} + +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er) { + this.statCache[abs] = false + return cb() + } + + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat + + if (abs.slice(-1) === '/' && !stat.isDirectory()) + return cb(null, false, stat) + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return cb() + + return cb(null, c, stat) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./sync.js":17,"_process":24,"assert":9,"events":14,"fs":12,"inflight":18,"inherits":19,"minimatch":20,"once":21,"path":22,"path-is-absolute":23,"util":28}],17:[function(require,module,exports){ +(function (process){ +module.exports = globSync +globSync.GlobSync = GlobSync + +var fs = require('fs') +var minimatch = require('minimatch') +var Minimatch = minimatch.Minimatch +var Glob = require('./glob.js').Glob +var util = require('util') +var path = require('path') +var assert = require('assert') +var isAbsolute = require('path-is-absolute') +var common = require('./common.js') +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored + +function globSync (pattern, options) { + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + return new GlobSync(pattern, options).found +} + +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') + + if (typeof options === 'function' || arguments.length === 3) + throw new TypeError('callback provided to sync glob\n'+ + 'See: https://github.com/isaacs/node-glob/issues/167') + + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + + setopts(this, pattern, options) + + if (this.noprocess) + return this + + var n = this.minimatch.set.length + this.matches = new Array(n) + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false) + } + this._finish() +} + +GlobSync.prototype._finish = function () { + assert(this instanceof GlobSync) + if (this.realpath) { + var self = this + this.matches.forEach(function (matchset, index) { + var set = self.matches[index] = Object.create(null) + for (var p in matchset) { + try { + p = self._makeAbs(p) + var real = fs.realpathSync(p, self.realpathCache) + set[real] = true + } catch (er) { + if (er.syscall === 'stat') + set[self._makeAbs(p)] = true + else + throw er + } + } + }) + } + common.finish(this) +} + + +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === 'string') { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // See if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + this._processSimple(pattern.join('/'), index) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's 'absolute' like /foo/bar, + // or 'relative' like '../baz' + prefix = pattern.slice(0, n).join('/') + break + } + + var remain = pattern.slice(n) + + // get the list of entries. + var read + if (prefix === null) + read = '.' + else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { + if (!prefix || !isAbsolute(prefix)) + prefix = '/' + prefix + read = prefix + } else + read = prefix + + var abs = this._makeAbs(read) + + //if ignored, skip processing + if (childrenIgnored(this, read)) + return + + var isGlobStar = remain[0] === minimatch.GLOBSTAR + if (isGlobStar) + this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) + else + this._processReaddir(prefix, read, abs, remain, index, inGlobStar) +} + + +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) + + // if the abs isn't a dir, then nothing can match! + if (!entries) + return + + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = remain[0] + var negate = !!this.minimatch.negate + var rawGlob = pn._glob + var dotOk = this.dot || rawGlob.charAt(0) === '.' + + var matchedEntries = [] + for (var i = 0; i < entries.length; i++) { + var e = entries[i] + if (e.charAt(0) !== '.' || dotOk) { + var m + if (negate && !prefix) { + m = !e.match(pn) + } else { + m = e.match(pn) + } + if (m) + matchedEntries.push(e) + } + } + + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return + + // if this is the last remaining pattern bit, then no need for + // an additional stat *unless* the user has specified mark or + // stat explicitly. We know they exist, since readdir returned + // them. + + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } + + if (e.charAt(0) === '/' && !this.nomount) { + e = path.join(this.root, e) + } + this.matches[index][e] = true + } + // This was the last one, and no stats were needed + return + } + + // now test all matched entries as stand-ins for that part + // of the pattern. + remain.shift() + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + var newPattern + if (prefix) + newPattern = [prefix, e] + else + newPattern = [e] + this._process(newPattern.concat(remain), index, inGlobStar) + } +} + + +GlobSync.prototype._emitMatch = function (index, e) { + var abs = this._makeAbs(e) + if (this.mark) + e = this._mark(e) + + if (this.matches[index][e]) + return + + if (this.nodir) { + var c = this.cache[this._makeAbs(e)] + if (c === 'DIR' || Array.isArray(c)) + return + } + + this.matches[index][e] = true + if (this.stat) + this._stat(e) +} + + +GlobSync.prototype._readdirInGlobStar = function (abs) { + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false) + + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + // lstat failed, doesn't exist + return null + } + + var isSym = lstat.isSymbolicLink() + this.symlinks[abs] = isSym + + // If it's not a symlink or a dir, then it's definitely a regular file. + // don't bother doing a readdir in that case. + if (!isSym && !lstat.isDirectory()) + this.cache[abs] = 'FILE' + else + entries = this._readdir(abs, false) + + return entries +} + +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries + + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) + + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null + + if (Array.isArray(c)) + return c + } + + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} + +GlobSync.prototype._readdirEntries = function (abs, entries) { + // if we haven't asked to stat everything, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. + if (!this.mark && !this.stat) { + for (var i = 0; i < entries.length; i ++) { + var e = entries[i] + if (abs === '/') + e = abs + e + else + e = abs + '/' + e + this.cache[e] = true + } + } + + this.cache[abs] = entries + + // mark and cache dir-ness + return entries +} + +GlobSync.prototype._readdirError = function (f, er) { + // handle errors, and cache the information + switch (er.code) { + case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 + case 'ENOTDIR': // totally normal. means it *does* exist. + this.cache[this._makeAbs(f)] = 'FILE' + break + + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break + + default: // some unusual error. Treat as failure. + this.cache[this._makeAbs(f)] = false + if (this.strict) + throw er + if (!this.silent) + console.error('glob error', er) + break + } +} + +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + + var entries = this._readdir(abs, inGlobStar) + + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return + + // test without the globstar, and with every child both below + // and replacing the globstar. + var remainWithoutGlobStar = remain.slice(1) + var gspref = prefix ? [ prefix ] : [] + var noGlobStar = gspref.concat(remainWithoutGlobStar) + + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) + + var len = entries.length + var isSym = this.symlinks[abs] + + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return + + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue + + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true) + + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) + } +} + +GlobSync.prototype._processSimple = function (prefix, index) { + // XXX review this. Shouldn't it be doing the mounting etc + // before doing stat? kinda weird? + var exists = this._stat(prefix) + + if (!this.matches[index]) + this.matches[index] = Object.create(null) + + // If it doesn't exist, then just mark the lack of results + if (!exists) + return + + if (prefix && isAbsolute(prefix) && !this.nomount) { + var trail = /[\/\\]$/.test(prefix) + if (prefix.charAt(0) === '/') { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + if (trail) + prefix += '/' + } + } + + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + + // Mark this as a match + this.matches[index][prefix] = true +} + +// Returns either 'DIR', 'FILE', or false +GlobSync.prototype._stat = function (f) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' + + if (f.length > this.maxLength) + return false + + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] + + if (Array.isArray(c)) + c = 'DIR' + + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return c + + if (needDir && c === 'FILE') + return false + + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } + + var exists + var stat = this.statCache[abs] + if (!stat) { + var lstat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + return false + } + + if (lstat.isSymbolicLink()) { + try { + stat = fs.statSync(abs) + } catch (er) { + stat = lstat + } + } else { + stat = lstat + } + } + + this.statCache[abs] = stat + + var c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + + if (needDir && c !== 'DIR') + return false + + return c +} + +GlobSync.prototype._mark = function (p) { + return common.mark(this, p) +} + +GlobSync.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} + +}).call(this,require('_process')) +},{"./common.js":15,"./glob.js":16,"_process":24,"assert":9,"fs":12,"minimatch":20,"path":22,"path-is-absolute":23,"util":28}],18:[function(require,module,exports){ +(function (process){ +var wrappy = require('wrappy') +var reqs = Object.create(null) +var once = require('once') + +module.exports = wrappy(inflight) + +function inflight (key, cb) { + if (reqs[key]) { + reqs[key].push(cb) + return null + } else { + reqs[key] = [cb] + return makeres(key) + } +} + +function makeres (key) { + return once(function RES () { + var cbs = reqs[key] + var len = cbs.length + var args = slice(arguments) + + // XXX It's somewhat ambiguous whether a new callback added in this + // pass should be queued for later execution if something in the + // list of callbacks throws, or if it should just be discarded. + // However, it's such an edge case that it hardly matters, and either + // choice is likely as surprising as the other. + // As it happens, we do go ahead and schedule it for later execution. + try { + for (var i = 0; i < len; i++) { + cbs[i].apply(null, args) + } + } finally { + if (cbs.length > len) { + // added more in the interim. + // de-zalgo, just in case, but don't call again. + cbs.splice(0, len) + process.nextTick(function () { + RES.apply(null, args) + }) + } else { + delete reqs[key] + } + } + }) +} + +function slice (args) { + var length = args.length + var array = [] + + for (var i = 0; i < length; i++) array[i] = args[i] + return array +} + +}).call(this,require('_process')) +},{"_process":24,"once":21,"wrappy":29}],19:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} + +},{}],20:[function(require,module,exports){ +module.exports = minimatch +minimatch.Minimatch = Minimatch + +var path = { sep: '/' } +try { + path = require('path') +} catch (er) {} + +var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} +var expand = require('brace-expansion') + +var plTypes = { + '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, + '?': { open: '(?:', close: ')?' }, + '+': { open: '(?:', close: ')+' }, + '*': { open: '(?:', close: ')*' }, + '@': { open: '(?:', close: ')' } +} + +// any single thing other than / +// don't need to escape / when using new RegExp() +var qmark = '[^/]' + +// * => any number of characters +var star = qmark + '*?' + +// ** when dots are allowed. Anything goes, except .. and . +// not (^ or / followed by one or two dots followed by $ or /), +// followed by anything, any number of times. +var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' + +// not a ^ or / followed by a dot, +// followed by anything, any number of times. +var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' + +// characters that need to be escaped in RegExp. +var reSpecials = charSet('().*{}+?[]^$\\!') + +// "abc" -> { a:true, b:true, c:true } +function charSet (s) { + return s.split('').reduce(function (set, c) { + set[c] = true + return set + }, {}) +} + +// normalizes slashes. +var slashSplit = /\/+/ + +minimatch.filter = filter +function filter (pattern, options) { + options = options || {} + return function (p, i, list) { + return minimatch(p, pattern, options) + } +} + +function ext (a, b) { + a = a || {} + b = b || {} + var t = {} + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) + Object.keys(a).forEach(function (k) { + t[k] = a[k] + }) + return t +} + +minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return minimatch + + var orig = minimatch + + var m = function minimatch (p, pattern, options) { + return orig.minimatch(p, pattern, ext(def, options)) + } + + m.Minimatch = function Minimatch (pattern, options) { + return new orig.Minimatch(pattern, ext(def, options)) + } + + return m +} + +Minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return Minimatch + return minimatch.defaults(def).Minimatch +} + +function minimatch (p, pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + return false + } + + // "" only matches "" + if (pattern.trim() === '') return p === '' + + return new Minimatch(pattern, options).match(p) +} + +function Minimatch (pattern, options) { + if (!(this instanceof Minimatch)) { + return new Minimatch(pattern, options) + } + + if (typeof pattern !== 'string') { + throw new TypeError('glob pattern string required') + } + + if (!options) options = {} + pattern = pattern.trim() + + // windows support: need to use /, not \ + if (path.sep !== '/') { + pattern = pattern.split(path.sep).join('/') + } + + this.options = options + this.set = [] + this.pattern = pattern + this.regexp = null + this.negate = false + this.comment = false + this.empty = false + + // make the set of regexps etc. + this.make() +} + +Minimatch.prototype.debug = function () {} + +Minimatch.prototype.make = make +function make () { + // don't do it more than once. + if (this._made) return + + var pattern = this.pattern + var options = this.options + + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + this.comment = true + return + } + if (!pattern) { + this.empty = true + return + } + + // step 1: figure out negation, etc. + this.parseNegate() + + // step 2: expand braces + var set = this.globSet = this.braceExpand() + + if (options.debug) this.debug = console.error + + this.debug(this.pattern, set) + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + set = this.globParts = set.map(function (s) { + return s.split(slashSplit) + }) + + this.debug(this.pattern, set) + + // glob --> regexps + set = set.map(function (s, si, set) { + return s.map(this.parse, this) + }, this) + + this.debug(this.pattern, set) + + // filter out everything that didn't compile properly. + set = set.filter(function (s) { + return s.indexOf(false) === -1 + }) + + this.debug(this.pattern, set) + + this.set = set +} + +Minimatch.prototype.parseNegate = parseNegate +function parseNegate () { + var pattern = this.pattern + var negate = false + var options = this.options + var negateOffset = 0 + + if (options.nonegate) return + + for (var i = 0, l = pattern.length + ; i < l && pattern.charAt(i) === '!' + ; i++) { + negate = !negate + negateOffset++ + } + + if (negateOffset) this.pattern = pattern.substr(negateOffset) + this.negate = negate +} + +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +minimatch.braceExpand = function (pattern, options) { + return braceExpand(pattern, options) +} + +Minimatch.prototype.braceExpand = braceExpand + +function braceExpand (pattern, options) { + if (!options) { + if (this instanceof Minimatch) { + options = this.options + } else { + options = {} + } + } + + pattern = typeof pattern === 'undefined' + ? this.pattern : pattern + + if (typeof pattern === 'undefined') { + throw new TypeError('undefined pattern') + } + + if (options.nobrace || + !pattern.match(/\{.*\}/)) { + // shortcut. no need to expand. + return [pattern] + } + + return expand(pattern) +} + +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +Minimatch.prototype.parse = parse +var SUBPARSE = {} +function parse (pattern, isSub) { + if (pattern.length > 1024 * 64) { + throw new TypeError('pattern is too long') + } + + var options = this.options + + // shortcuts + if (!options.noglobstar && pattern === '**') return GLOBSTAR + if (pattern === '') return '' + + var re = '' + var hasMagic = !!options.nocase + var escaping = false + // ? => one single character + var patternListStack = [] + var negativeLists = [] + var stateChar + var inClass = false + var reClassStart = -1 + var classStart = -1 + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + var patternStart = pattern.charAt(0) === '.' ? '' // anything + // not (start or / followed by . or .. followed by / or end) + : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' + : '(?!\\.)' + var self = this + + function clearStateChar () { + if (stateChar) { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) { + case '*': + re += star + hasMagic = true + break + case '?': + re += qmark + hasMagic = true + break + default: + re += '\\' + stateChar + break + } + self.debug('clearStateChar %j %j', stateChar, re) + stateChar = false + } + } + + for (var i = 0, len = pattern.length, c + ; (i < len) && (c = pattern.charAt(i)) + ; i++) { + this.debug('%s\t%s %s %j', pattern, i, re, c) + + // skip over any that are escaped. + if (escaping && reSpecials[c]) { + re += '\\' + c + escaping = false + continue + } + + switch (c) { + case '/': + // completely not allowed, even escaped. + // Should already be path-split by now. + return false + + case '\\': + clearStateChar() + escaping = true + continue + + // the various stateChar values + // for the "extglob" stuff. + case '?': + case '*': + case '+': + case '@': + case '!': + this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) + + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) { + this.debug(' in class') + if (c === '!' && i === classStart + 1) c = '^' + re += c + continue + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + self.debug('call clearStateChar %j', stateChar) + clearStateChar() + stateChar = c + // if extglob is disabled, then +(asdf|foo) isn't a thing. + // just clear the statechar *now*, rather than even diving into + // the patternList stuff. + if (options.noext) clearStateChar() + continue + + case '(': + if (inClass) { + re += '(' + continue + } + + if (!stateChar) { + re += '\\(' + continue + } + + patternListStack.push({ + type: stateChar, + start: i - 1, + reStart: re.length, + open: plTypes[stateChar].open, + close: plTypes[stateChar].close + }) + // negation is (?:(?!js)[^/]*) + re += stateChar === '!' ? '(?:(?!(?:' : '(?:' + this.debug('plType %j %j', stateChar, re) + stateChar = false + continue + + case ')': + if (inClass || !patternListStack.length) { + re += '\\)' + continue + } + + clearStateChar() + hasMagic = true + var pl = patternListStack.pop() + // negation is (?:(?!js)[^/]*) + // The others are (?:) + re += pl.close + if (pl.type === '!') { + negativeLists.push(pl) + } + pl.reEnd = re.length + continue + + case '|': + if (inClass || !patternListStack.length || escaping) { + re += '\\|' + escaping = false + continue + } + + clearStateChar() + re += '|' + continue + + // these are mostly the same in regexp and glob + case '[': + // swallow any state-tracking char before the [ + clearStateChar() + + if (inClass) { + re += '\\' + c + continue + } + + inClass = true + classStart = i + reClassStart = re.length + re += c + continue + + case ']': + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i === classStart + 1 || !inClass) { + re += '\\' + c + escaping = false + continue + } + + // handle the case where we left a class open. + // "[z-a]" is valid, equivalent to "\[z-a\]" + if (inClass) { + // split where the last [ was, make sure we don't have + // an invalid re. if so, re-walk the contents of the + // would-be class to re-translate any characters that + // were passed through as-is + // TODO: It would probably be faster to determine this + // without a try/catch and a new RegExp, but it's tricky + // to do safely. For now, this is safe and works. + var cs = pattern.substring(classStart + 1, i) + try { + RegExp('[' + cs + ']') + } catch (er) { + // not a valid class! + var sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' + hasMagic = hasMagic || sp[1] + inClass = false + continue + } + } + + // finish up the class. + hasMagic = true + inClass = false + re += c + continue + + default: + // swallow any state char that wasn't consumed + clearStateChar() + + if (escaping) { + // no need + escaping = false + } else if (reSpecials[c] + && !(c === '^' && inClass)) { + re += '\\' + } + + re += c + + } // switch + } // for + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + cs = pattern.substr(classStart + 1) + sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + hasMagic = hasMagic || sp[1] + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { + var tail = re.slice(pl.reStart + pl.open.length) + this.debug('setting tail', re, pl) + // maybe some even number of \, then maybe 1 \, followed by a | + tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { + if (!$2) { + // the | isn't already escaped, so escape it. + $2 = '\\' + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return $1 + $1 + $2 + '|' + }) + + this.debug('tail=%j\n %s', tail, tail, pl, re) + var t = pl.type === '*' ? star + : pl.type === '?' ? qmark + : '\\' + pl.type + + hasMagic = true + re = re.slice(0, pl.reStart) + t + '\\(' + tail + } + + // handle trailing things that only matter at the very end. + clearStateChar() + if (escaping) { + // trailing \\ + re += '\\\\' + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = false + switch (re.charAt(0)) { + case '.': + case '[': + case '(': addPatternStart = true + } + + // Hack to work around lack of negative lookbehind in JS + // A pattern like: *.!(x).!(y|z) needs to ensure that a name + // like 'a.xyz.yz' doesn't match. So, the first negative + // lookahead, has to look ALL the way ahead, to the end of + // the pattern. + for (var n = negativeLists.length - 1; n > -1; n--) { + var nl = negativeLists[n] + + var nlBefore = re.slice(0, nl.reStart) + var nlFirst = re.slice(nl.reStart, nl.reEnd - 8) + var nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + var nlAfter = re.slice(nl.reEnd) + + nlLast += nlAfter + + // Handle nested stuff like *(*.js|!(*.json)), where open parens + // mean that we should *not* include the ) in the bit that is considered + // "after" the negated section. + var openParensBefore = nlBefore.split('(').length - 1 + var cleanAfter = nlAfter + for (i = 0; i < openParensBefore; i++) { + cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') + } + nlAfter = cleanAfter + + var dollar = '' + if (nlAfter === '' && isSub !== SUBPARSE) { + dollar = '$' + } + var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast + re = newRe + } + + // if the re is not "" at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re !== '' && hasMagic) { + re = '(?=.)' + re + } + + if (addPatternStart) { + re = patternStart + re + } + + // parsing just a piece of a larger pattern. + if (isSub === SUBPARSE) { + return [re, hasMagic] + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) { + return globUnescape(pattern) + } + + var flags = options.nocase ? 'i' : '' + try { + var regExp = new RegExp('^' + re + '$', flags) + } catch (er) { + // If it was an invalid regular expression, then it can't match + // anything. This trick looks for a character after the end of + // the string, which is of course impossible, except in multi-line + // mode, but it's not a /m regex. + return new RegExp('$.') + } + + regExp._glob = pattern + regExp._src = re + + return regExp +} + +minimatch.makeRe = function (pattern, options) { + return new Minimatch(pattern, options || {}).makeRe() +} + +Minimatch.prototype.makeRe = makeRe +function makeRe () { + if (this.regexp || this.regexp === false) return this.regexp + + // at this point, this.set is a 2d array of partial + // pattern strings, or "**". + // + // It's better to use .match(). This function shouldn't + // be used, really, but it's pretty convenient sometimes, + // when you just want to work with a regex. + var set = this.set + + if (!set.length) { + this.regexp = false + return this.regexp + } + var options = this.options + + var twoStar = options.noglobstar ? star + : options.dot ? twoStarDot + : twoStarNoDot + var flags = options.nocase ? 'i' : '' + + var re = set.map(function (pattern) { + return pattern.map(function (p) { + return (p === GLOBSTAR) ? twoStar + : (typeof p === 'string') ? regExpEscape(p) + : p._src + }).join('\\\/') + }).join('|') + + // must match entire pattern + // ending in a * or ** will make it less strict. + re = '^(?:' + re + ')$' + + // can match anything, as long as it's not this. + if (this.negate) re = '^(?!' + re + ').*$' + + try { + this.regexp = new RegExp(re, flags) + } catch (ex) { + this.regexp = false + } + return this.regexp +} + +minimatch.match = function (list, pattern, options) { + options = options || {} + var mm = new Minimatch(pattern, options) + list = list.filter(function (f) { + return mm.match(f) + }) + if (mm.options.nonull && !list.length) { + list.push(pattern) + } + return list +} + +Minimatch.prototype.match = match +function match (f, partial) { + this.debug('match', f, this.pattern) + // short-circuit in the case of busted things. + // comments, etc. + if (this.comment) return false + if (this.empty) return f === '' + + if (f === '/' && partial) return true + + var options = this.options + + // windows: need to use /, not \ + if (path.sep !== '/') { + f = f.split(path.sep).join('/') + } + + // treat the test path as a set of pathparts. + f = f.split(slashSplit) + this.debug(this.pattern, 'split', f) + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + + var set = this.set + this.debug(this.pattern, 'set', set) + + // Find the basename of the path by looking for the last non-empty segment + var filename + var i + for (i = f.length - 1; i >= 0; i--) { + filename = f[i] + if (filename) break + } + + for (i = 0; i < set.length; i++) { + var pattern = set[i] + var file = f + if (options.matchBase && pattern.length === 1) { + file = [filename] + } + var hit = this.matchOne(file, pattern, partial) + if (hit) { + if (options.flipNegate) return true + return !this.negate + } + } + + // didn't get any hits. this is success if it's a negative + // pattern, failure otherwise. + if (options.flipNegate) return false + return this.negate +} + +// set partial to true to test if, for example, +// "/a/b" matches the start of "/*/b/*/d" +// Partial means, if you run out of file before you run +// out of pattern, then that's fine, as long as all +// the parts match. +Minimatch.prototype.matchOne = function (file, pattern, partial) { + var options = this.options + + this.debug('matchOne', + { 'this': this, file: file, pattern: pattern }) + + this.debug('matchOne', file.length, pattern.length) + + for (var fi = 0, + pi = 0, + fl = file.length, + pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi++, pi++) { + this.debug('matchOne loop') + var p = pattern[pi] + var f = file[fi] + + this.debug(pattern, p, f) + + // should be impossible. + // some invalid regexp stuff in the set. + if (p === false) return false + + if (p === GLOBSTAR) { + this.debug('GLOBSTAR', [pattern, p, f]) + + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var fr = fi + var pr = pi + 1 + if (pr === pl) { + this.debug('** at the end') + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for (; fi < fl; fi++) { + if (file[fi] === '.' || file[fi] === '..' || + (!options.dot && file[fi].charAt(0) === '.')) return false + } + return true + } + + // ok, let's see if we can swallow whatever we can. + while (fr < fl) { + var swallowee = file[fr] + + this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) + + // XXX remove this slice. Just pass the start index. + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { + this.debug('globstar found match!', fr, fl, swallowee) + // found a match. + return true + } else { + // can't swallow "." or ".." ever. + // can only swallow ".foo" when explicitly asked. + if (swallowee === '.' || swallowee === '..' || + (!options.dot && swallowee.charAt(0) === '.')) { + this.debug('dot detected!', file, fr, pattern, pr) + break + } + + // ** swallows a segment, and continue. + this.debug('globstar swallow a segment, and continue') + fr++ + } + } + + // no match was found. + // However, in partial mode, we can't say this is necessarily over. + // If there's more *pattern* left, then + if (partial) { + // ran out of file + this.debug('\n>>> no match, partial?', file, fr, pattern, pr) + if (fr === fl) return true + } + return false + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + var hit + if (typeof p === 'string') { + if (options.nocase) { + hit = f.toLowerCase() === p.toLowerCase() + } else { + hit = f === p + } + this.debug('string match', p, f, hit) + } else { + hit = f.match(p) + this.debug('pattern match', p, f, hit) + } + + if (!hit) return false + } + + // Note: ending in / means that we'll get a final "" + // at the end of the pattern. This can only match a + // corresponding "" at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though "" matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (fi === fl && pi === pl) { + // ran out of pattern and filename at the same time. + // an exact hit! + return true + } else if (fi === fl) { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return partial + } else if (pi === pl) { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') + return emptyFileEnd + } + + // should be unreachable. + throw new Error('wtf?') +} + +// replace stuff like \* with * +function globUnescape (s) { + return s.replace(/\\(.)/g, '$1') +} + +function regExpEscape (s) { + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') +} + +},{"brace-expansion":11,"path":22}],21:[function(require,module,exports){ +var wrappy = require('wrappy') +module.exports = wrappy(once) +module.exports.strict = wrappy(onceStrict) + +once.proto = once(function () { + Object.defineProperty(Function.prototype, 'once', { + value: function () { + return once(this) + }, + configurable: true + }) + + Object.defineProperty(Function.prototype, 'onceStrict', { + value: function () { + return onceStrict(this) + }, + configurable: true + }) +}) + +function once (fn) { + var f = function () { + if (f.called) return f.value + f.called = true + return f.value = fn.apply(this, arguments) + } + f.called = false + return f +} + +function onceStrict (fn) { + var f = function () { + if (f.called) + throw new Error(f.onceError) + f.called = true + return f.value = fn.apply(this, arguments) + } + var name = fn.name || 'Function wrapped with `once`' + f.onceError = name + " shouldn't be called more than once" + f.called = false + return f +} + +},{"wrappy":29}],22:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":24}],23:[function(require,module,exports){ +(function (process){ +'use strict'; + +function posix(path) { + return path.charAt(0) === '/'; +} + +function win32(path) { + // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56 + var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/; + var result = splitDeviceRe.exec(path); + var device = result[1] || ''; + var isUnc = Boolean(device && device.charAt(1) !== ':'); + + // UNC paths are always absolute + return Boolean(result[2] || isUnc); +} + +module.exports = process.platform === 'win32' ? win32 : posix; +module.exports.posix = posix; +module.exports.win32 = win32; + +}).call(this,require('_process')) +},{"_process":24}],24:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],25:[function(require,module,exports){ +// Underscore.js 1.8.3 +// http://underscorejs.org +// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof define === 'function' && define.amd) { + define('underscore', [], function() { + return _; + }); + } +}.call(this)); + +},{}],26:[function(require,module,exports){ +arguments[4][19][0].apply(exports,arguments) +},{"dup":19}],27:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],28:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + if (process.noDeprecation === true) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./support/isBuffer":27,"_process":24,"inherits":26}],29:[function(require,module,exports){ +// Returns a wrapper function that returns a wrapped callback +// The wrapper function should do some stuff, and return a +// presumably different callback function. +// This makes sure that own properties are retained, so that +// decorations and such are not lost along the way. +module.exports = wrappy +function wrappy (fn, cb) { + if (fn && cb) return wrappy(fn)(cb) + + if (typeof fn !== 'function') + throw new TypeError('need wrapper function') + + Object.keys(fn).forEach(function (k) { + wrapper[k] = fn[k] + }) + + return wrapper + + function wrapper() { + var args = new Array(arguments.length) + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i] + } + var ret = fn.apply(this, args) + var cb = args[args.length-1] + if (typeof ret === 'function' && ret !== cb) { + Object.keys(cb).forEach(function (k) { + ret[k] = cb[k] + }) + } + return ret + } +} + +},{}]},{},[7])(7) +}); \ No newline at end of file diff --git a/assets/javascripts/workers/search.409db549.min.js b/assets/javascripts/workers/search.409db549.min.js new file mode 100644 index 0000000..241f882 --- /dev/null +++ b/assets/javascripts/workers/search.409db549.min.js @@ -0,0 +1,48 @@ +(()=>{var ge=Object.create;var z=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames,G=Object.getOwnPropertySymbols,ve=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var X=(t,e,r)=>e in t?z(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,Z=(t,e)=>{for(var r in e||(e={}))J.call(e,r)&&X(t,r,e[r]);if(G)for(var r of G(e))xe.call(e,r)&&X(t,r,e[r]);return t};var Se=t=>z(t,"__esModule",{value:!0});var K=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Qe=(t,e,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of me(e))!J.call(t,n)&&n!=="default"&&z(t,n,{get:()=>e[n],enumerable:!(r=ye(e,n))||r.enumerable});return t},W=t=>Qe(Se(z(t!=null?ge(ve(t)):{},"default",t&&t.__esModule&&"default"in t?{get:()=>t.default,enumerable:!0}:{value:t,enumerable:!0})),t);var U=(t,e,r)=>new Promise((n,i)=>{var s=u=>{try{a(r.next(u))}catch(c){i(c)}},o=u=>{try{a(r.throw(u))}catch(c){i(c)}},a=u=>u.done?n(u.value):Promise.resolve(u.value).then(s,o);a((r=r.apply(t,e)).next())});var re=K((ee,te)=>{/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */(function(){var t=function(e){var r=new t.Builder;return r.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),r.searchPipeline.add(t.stemmer),e.call(r,r),r.build()};t.version="2.3.9";/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */t.utils={},t.utils.warn=function(e){return function(r){e.console&&console.warn&&console.warn(r)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var r=Object.create(null),n=Object.keys(e),i=0;i0){var h=t.utils.clone(r)||{};h.position=[a,c],h.index=s.length,s.push(new t.Token(n.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,r){r in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+r),e.label=r,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var r=e.label&&e.label in this.registeredFunctions;r||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var r=new t.Pipeline;return e.forEach(function(n){var i=t.Pipeline.registeredFunctions[n];if(i)r.add(i);else throw new Error("Cannot load unregistered function: "+n)}),r},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(r){t.Pipeline.warnIfFunctionNotRegistered(r),this._stack.push(r)},this)},t.Pipeline.prototype.after=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");n=n+1,this._stack.splice(n,0,r)},t.Pipeline.prototype.before=function(e,r){t.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(e);if(n==-1)throw new Error("Cannot find existingFn");this._stack.splice(n,0,r)},t.Pipeline.prototype.remove=function(e){var r=this._stack.indexOf(e);r!=-1&&this._stack.splice(r,1)},t.Pipeline.prototype.run=function(e){for(var r=this._stack.length,n=0;n1&&(oe&&(n=s),o!=e);)i=n-r,s=r+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(r+=n[c+1]*i[h+1],c+=2,h+=2);return r},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),r=1,n=0;r0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}s.str.length==1&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),y=s.str.charAt(1),g;y in s.node.edges?g=s.node.edges[y]:(g=new t.TokenSet,s.node.edges[y]=g),s.str.length==1&&(g.final=!0),i.push({node:g,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return n},t.TokenSet.fromString=function(e){for(var r=new t.TokenSet,n=r,i=0,s=e.length;i=e;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(r){var n=new t.QueryParser(e,r);n.parse()})},t.Index.prototype.query=function(e){for(var r=new t.Query(this.fields),n=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,r){var n=e[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,r;do e=this.next(),r=e.charCodeAt(0);while(r>47&&r<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var r=e.next();if(r==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){e.escapeCharacter();continue}if(r==":")return t.QueryLexer.lexField;if(r=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(r=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(r=="+"&&e.width()===1||r=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(r.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,r){this.lexer=new t.QueryLexer(e),this.query=r,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var r=e.peekLexeme();if(r!=null)switch(r.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new t.QueryParseError(n,r.start,r.end)}},t.QueryParser.parsePresence=function(e){var r=e.consumeLexeme();if(r!=null){switch(r.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new t.QueryParseError(n,r.start,r.end)}var i=e.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new t.QueryParseError(n,r.start,r.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(n,i.start,i.end)}}},t.QueryParser.parseField=function(e){var r=e.consumeLexeme();if(r!=null){if(e.query.allFields.indexOf(r.str)==-1){var n=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.fields=[r.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,r.start,r.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var r=e.consumeLexeme();if(r!=null){e.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(n==null){e.nextClause();return}switch(n.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new t.QueryParseError(i,n.start,n.end)}}},t.QueryParser.parseEditDistance=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.editDistance=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.boost=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,r){typeof define=="function"&&define.amd?define(r):typeof ee=="object"?te.exports=r():e.lunr=r()}(this,function(){return t})})()});var H=K((Ie,ne)=>{/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */"use strict";var be=/["'&<>]/;ne.exports=we;function we(t){var e=""+t,r=be.exec(e);if(!r)return e;var n,i="",s=0,o=0;for(s=r.index;s`${s}${o}`;return i=>{i=i.replace(/[\s*+\-:~^]+/g," ").trim();let s=new RegExp(`(^|${t.separator})(${i.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return o=>(e?(0,oe.default)(o):o).replace(s,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ue(t){let e=new lunr.Query(["title","text"]);return new lunr.QueryParser(t,e).parse(),e.clauses}function ce(t,e){let r=new Set(t),n={};for(let i=0;i!n.has(i)))]}var q=class{constructor({config:e,docs:r,index:n,options:i}){this.options=i,this.documents=se(r),this.highlight=ae(e,!1),lunr.tokenizer.separator=new RegExp(e.separator),typeof n=="undefined"?this.index=lunr(function(){e.lang.length===1&&e.lang[0]!=="en"?this.use(lunr[e.lang[0]]):e.lang.length>1&&this.use(lunr.multiLanguage(...e.lang));let s=Le(["trimmer","stopWordFilter","stemmer"],i.pipeline);for(let o of e.lang.map(a=>a==="en"?lunr:lunr[a]))for(let a of s)this.pipeline.remove(o[a]),this.searchPipeline.remove(o[a]);this.ref("location"),this.field("title",{boost:1e3}),this.field("text");for(let o of r)this.add(o)}):this.index=lunr.Index.load(n)}search(e){if(e)try{let r=this.highlight(e),n=ue(e).filter(o=>o.presence!==lunr.Query.presence.PROHIBITED),i=this.index.search(`${e}*`).reduce((o,{ref:a,score:u,matchData:c})=>{let h=this.documents.get(a);if(typeof h!="undefined"){let{location:y,title:g,text:b,parent:v}=h,Q=ce(n,Object.keys(c.metadata)),f=+!v+ +Object.values(Q).every(p=>p);o.push({location:y,title:r(g),text:r(b),score:u*(1+f),terms:Q})}return o},[]).sort((o,a)=>a.score-o.score).reduce((o,a)=>{let u=this.documents.get(a.location);if(typeof u!="undefined"){let c="parent"in u?u.parent.location:u.location;o.set(c,[...o.get(c)||[],a])}return o},new Map),s;if(this.options.suggestions){let o=this.index.query(a=>{for(let u of n)a.term(u.term,{fields:["title"],presence:lunr.Query.presence.REQUIRED,wildcard:lunr.Query.wildcard.TRAILING})});s=o.length?Object.keys(o[0].matchData.metadata):[]}return Z({items:[...i.values()]},typeof s!="undefined"&&{suggestions:s})}catch(r){console.warn(`Invalid query: ${e} \u2013 see https://bit.ly/2s3ChXG`)}return{items:[]}}};var T;(function(i){i[i.SETUP=0]="SETUP",i[i.READY=1]="READY",i[i.QUERY=2]="QUERY",i[i.RESULT=3]="RESULT"})(T||(T={}));var Y;function Ee(t){return U(this,null,function*(){let e="../lunr";if(typeof parent!="undefined"&&"IFrameWorker"in parent){let n=document.querySelector("script[src]"),[i]=n.src.split("/worker");e=e.replace("..",i)}let r=[];for(let n of t.lang){switch(n){case"ja":r.push(`${e}/tinyseg.js`);break;case"hi":case"th":r.push(`${e}/wordcut.js`);break}n!=="en"&&r.push(`${e}/min/lunr.${n}.min.js`)}t.lang.length>1&&r.push(`${e}/min/lunr.multi.min.js`),r.length&&(yield importScripts(`${e}/min/lunr.stemmer.support.min.js`,...r))})}function ke(t){return U(this,null,function*(){switch(t.type){case T.SETUP:return yield Ee(t.data.config),Y=new q(t.data),{type:T.READY};case T.QUERY:return{type:T.RESULT,data:Y?Y.search(t.data):{items:[]}};default:throw new TypeError("Invalid message type")}})}self.lunr=le.default;addEventListener("message",t=>U(void 0,null,function*(){postMessage(yield ke(t.data))}));})(); +//# sourceMappingURL=search.409db549.min.js.map + diff --git a/assets/javascripts/workers/search.409db549.min.js.map b/assets/javascripts/workers/search.409db549.min.js.map new file mode 100644 index 0000000..b45f5f9 --- /dev/null +++ b/assets/javascripts/workers/search.409db549.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/lunr/lunr.js", "node_modules/escape-html/index.js", "src/assets/javascripts/integrations/search/worker/main/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/_/index.ts", "src/assets/javascripts/integrations/search/_/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts"], + "sourcesContent": ["/**\n * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9\n * Copyright (C) 2020 Oliver Nightingale\n * @license MIT\n */\n\n;(function(){\n\n/**\n * A convenience function for configuring and constructing\n * a new lunr Index.\n *\n * A lunr.Builder instance is created and the pipeline setup\n * with a trimmer, stop word filter and stemmer.\n *\n * This builder object is yielded to the configuration function\n * that is passed as a parameter, allowing the list of fields\n * and other builder parameters to be customised.\n *\n * All documents _must_ be added within the passed config function.\n *\n * @example\n * var idx = lunr(function () {\n * this.field('title')\n * this.field('body')\n * this.ref('id')\n *\n * documents.forEach(function (doc) {\n * this.add(doc)\n * }, this)\n * })\n *\n * @see {@link lunr.Builder}\n * @see {@link lunr.Pipeline}\n * @see {@link lunr.trimmer}\n * @see {@link lunr.stopWordFilter}\n * @see {@link lunr.stemmer}\n * @namespace {function} lunr\n */\nvar lunr = function (config) {\n var builder = new lunr.Builder\n\n builder.pipeline.add(\n lunr.trimmer,\n lunr.stopWordFilter,\n lunr.stemmer\n )\n\n builder.searchPipeline.add(\n lunr.stemmer\n )\n\n config.call(builder, builder)\n return builder.build()\n}\n\nlunr.version = \"2.3.9\"\n/*!\n * lunr.utils\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A namespace containing utils for the rest of the lunr library\n * @namespace lunr.utils\n */\nlunr.utils = {}\n\n/**\n * Print a warning message to the console.\n *\n * @param {String} message The message to be printed.\n * @memberOf lunr.utils\n * @function\n */\nlunr.utils.warn = (function (global) {\n /* eslint-disable no-console */\n return function (message) {\n if (global.console && console.warn) {\n console.warn(message)\n }\n }\n /* eslint-enable no-console */\n})(this)\n\n/**\n * Convert an object to a string.\n *\n * In the case of `null` and `undefined` the function returns\n * the empty string, in all other cases the result of calling\n * `toString` on the passed object is returned.\n *\n * @param {Any} obj The object to convert to a string.\n * @return {String} string representation of the passed object.\n * @memberOf lunr.utils\n */\nlunr.utils.asString = function (obj) {\n if (obj === void 0 || obj === null) {\n return \"\"\n } else {\n return obj.toString()\n }\n}\n\n/**\n * Clones an object.\n *\n * Will create a copy of an existing object such that any mutations\n * on the copy cannot affect the original.\n *\n * Only shallow objects are supported, passing a nested object to this\n * function will cause a TypeError.\n *\n * Objects with primitives, and arrays of primitives are supported.\n *\n * @param {Object} obj The object to clone.\n * @return {Object} a clone of the passed object.\n * @throws {TypeError} when a nested object is passed.\n * @memberOf Utils\n */\nlunr.utils.clone = function (obj) {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n var clone = Object.create(null),\n keys = Object.keys(obj)\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i],\n val = obj[key]\n\n if (Array.isArray(val)) {\n clone[key] = val.slice()\n continue\n }\n\n if (typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean') {\n clone[key] = val\n continue\n }\n\n throw new TypeError(\"clone is not deep and does not support nested objects\")\n }\n\n return clone\n}\nlunr.FieldRef = function (docRef, fieldName, stringValue) {\n this.docRef = docRef\n this.fieldName = fieldName\n this._stringValue = stringValue\n}\n\nlunr.FieldRef.joiner = \"/\"\n\nlunr.FieldRef.fromString = function (s) {\n var n = s.indexOf(lunr.FieldRef.joiner)\n\n if (n === -1) {\n throw \"malformed field ref string\"\n }\n\n var fieldRef = s.slice(0, n),\n docRef = s.slice(n + 1)\n\n return new lunr.FieldRef (docRef, fieldRef, s)\n}\n\nlunr.FieldRef.prototype.toString = function () {\n if (this._stringValue == undefined) {\n this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef\n }\n\n return this._stringValue\n}\n/*!\n * lunr.Set\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A lunr set.\n *\n * @constructor\n */\nlunr.Set = function (elements) {\n this.elements = Object.create(null)\n\n if (elements) {\n this.length = elements.length\n\n for (var i = 0; i < this.length; i++) {\n this.elements[elements[i]] = true\n }\n } else {\n this.length = 0\n }\n}\n\n/**\n * A complete set that contains all elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.complete = {\n intersect: function (other) {\n return other\n },\n\n union: function () {\n return this\n },\n\n contains: function () {\n return true\n }\n}\n\n/**\n * An empty set that contains no elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.empty = {\n intersect: function () {\n return this\n },\n\n union: function (other) {\n return other\n },\n\n contains: function () {\n return false\n }\n}\n\n/**\n * Returns true if this set contains the specified object.\n *\n * @param {object} object - Object whose presence in this set is to be tested.\n * @returns {boolean} - True if this set contains the specified object.\n */\nlunr.Set.prototype.contains = function (object) {\n return !!this.elements[object]\n}\n\n/**\n * Returns a new set containing only the elements that are present in both\n * this set and the specified set.\n *\n * @param {lunr.Set} other - set to intersect with this set.\n * @returns {lunr.Set} a new set that is the intersection of this and the specified set.\n */\n\nlunr.Set.prototype.intersect = function (other) {\n var a, b, elements, intersection = []\n\n if (other === lunr.Set.complete) {\n return this\n }\n\n if (other === lunr.Set.empty) {\n return other\n }\n\n if (this.length < other.length) {\n a = this\n b = other\n } else {\n a = other\n b = this\n }\n\n elements = Object.keys(a.elements)\n\n for (var i = 0; i < elements.length; i++) {\n var element = elements[i]\n if (element in b.elements) {\n intersection.push(element)\n }\n }\n\n return new lunr.Set (intersection)\n}\n\n/**\n * Returns a new set combining the elements of this and the specified set.\n *\n * @param {lunr.Set} other - set to union with this set.\n * @return {lunr.Set} a new set that is the union of this and the specified set.\n */\n\nlunr.Set.prototype.union = function (other) {\n if (other === lunr.Set.complete) {\n return lunr.Set.complete\n }\n\n if (other === lunr.Set.empty) {\n return this\n }\n\n return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements)))\n}\n/**\n * A function to calculate the inverse document frequency for\n * a posting. This is shared between the builder and the index\n *\n * @private\n * @param {object} posting - The posting for a given term\n * @param {number} documentCount - The total number of documents.\n */\nlunr.idf = function (posting, documentCount) {\n var documentsWithTerm = 0\n\n for (var fieldName in posting) {\n if (fieldName == '_index') continue // Ignore the term index, its not a field\n documentsWithTerm += Object.keys(posting[fieldName]).length\n }\n\n var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5)\n\n return Math.log(1 + Math.abs(x))\n}\n\n/**\n * A token wraps a string representation of a token\n * as it is passed through the text processing pipeline.\n *\n * @constructor\n * @param {string} [str=''] - The string token being wrapped.\n * @param {object} [metadata={}] - Metadata associated with this token.\n */\nlunr.Token = function (str, metadata) {\n this.str = str || \"\"\n this.metadata = metadata || {}\n}\n\n/**\n * Returns the token string that is being wrapped by this object.\n *\n * @returns {string}\n */\nlunr.Token.prototype.toString = function () {\n return this.str\n}\n\n/**\n * A token update function is used when updating or optionally\n * when cloning a token.\n *\n * @callback lunr.Token~updateFunction\n * @param {string} str - The string representation of the token.\n * @param {Object} metadata - All metadata associated with this token.\n */\n\n/**\n * Applies the given function to the wrapped string token.\n *\n * @example\n * token.update(function (str, metadata) {\n * return str.toUpperCase()\n * })\n *\n * @param {lunr.Token~updateFunction} fn - A function to apply to the token string.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.update = function (fn) {\n this.str = fn(this.str, this.metadata)\n return this\n}\n\n/**\n * Creates a clone of this token. Optionally a function can be\n * applied to the cloned token.\n *\n * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.clone = function (fn) {\n fn = fn || function (s) { return s }\n return new lunr.Token (fn(this.str, this.metadata), this.metadata)\n}\n/*!\n * lunr.tokenizer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A function for splitting a string into tokens ready to be inserted into\n * the search index. Uses `lunr.tokenizer.separator` to split strings, change\n * the value of this property to change how strings are split into tokens.\n *\n * This tokenizer will convert its parameter to a string by calling `toString` and\n * then will split this string on the character in `lunr.tokenizer.separator`.\n * Arrays will have their elements converted to strings and wrapped in a lunr.Token.\n *\n * Optional metadata can be passed to the tokenizer, this metadata will be cloned and\n * added as metadata to every token that is created from the object to be tokenized.\n *\n * @static\n * @param {?(string|object|object[])} obj - The object to convert into tokens\n * @param {?object} metadata - Optional metadata to associate with every token\n * @returns {lunr.Token[]}\n * @see {@link lunr.Pipeline}\n */\nlunr.tokenizer = function (obj, metadata) {\n if (obj == null || obj == undefined) {\n return []\n }\n\n if (Array.isArray(obj)) {\n return obj.map(function (t) {\n return new lunr.Token(\n lunr.utils.asString(t).toLowerCase(),\n lunr.utils.clone(metadata)\n )\n })\n }\n\n var str = obj.toString().toLowerCase(),\n len = str.length,\n tokens = []\n\n for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) {\n var char = str.charAt(sliceEnd),\n sliceLength = sliceEnd - sliceStart\n\n if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) {\n\n if (sliceLength > 0) {\n var tokenMetadata = lunr.utils.clone(metadata) || {}\n tokenMetadata[\"position\"] = [sliceStart, sliceLength]\n tokenMetadata[\"index\"] = tokens.length\n\n tokens.push(\n new lunr.Token (\n str.slice(sliceStart, sliceEnd),\n tokenMetadata\n )\n )\n }\n\n sliceStart = sliceEnd + 1\n }\n\n }\n\n return tokens\n}\n\n/**\n * The separator used to split a string into tokens. Override this property to change the behaviour of\n * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens.\n *\n * @static\n * @see lunr.tokenizer\n */\nlunr.tokenizer.separator = /[\\s\\-]+/\n/*!\n * lunr.Pipeline\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Pipelines maintain an ordered list of functions to be applied to all\n * tokens in documents entering the search index and queries being ran against\n * the index.\n *\n * An instance of lunr.Index created with the lunr shortcut will contain a\n * pipeline with a stop word filter and an English language stemmer. Extra\n * functions can be added before or after either of these functions or these\n * default functions can be removed.\n *\n * When run the pipeline will call each function in turn, passing a token, the\n * index of that token in the original list of all tokens and finally a list of\n * all the original tokens.\n *\n * The output of functions in the pipeline will be passed to the next function\n * in the pipeline. To exclude a token from entering the index the function\n * should return undefined, the rest of the pipeline will not be called with\n * this token.\n *\n * For serialisation of pipelines to work, all functions used in an instance of\n * a pipeline should be registered with lunr.Pipeline. Registered functions can\n * then be loaded. If trying to load a serialised pipeline that uses functions\n * that are not registered an error will be thrown.\n *\n * If not planning on serialising the pipeline then registering pipeline functions\n * is not necessary.\n *\n * @constructor\n */\nlunr.Pipeline = function () {\n this._stack = []\n}\n\nlunr.Pipeline.registeredFunctions = Object.create(null)\n\n/**\n * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token\n * string as well as all known metadata. A pipeline function can mutate the token string\n * or mutate (or add) metadata for a given token.\n *\n * A pipeline function can indicate that the passed token should be discarded by returning\n * null, undefined or an empty string. This token will not be passed to any downstream pipeline\n * functions and will not be added to the index.\n *\n * Multiple tokens can be returned by returning an array of tokens. Each token will be passed\n * to any downstream pipeline functions and all will returned tokens will be added to the index.\n *\n * Any number of pipeline functions may be chained together using a lunr.Pipeline.\n *\n * @interface lunr.PipelineFunction\n * @param {lunr.Token} token - A token from the document being processed.\n * @param {number} i - The index of this token in the complete list of tokens for this document/field.\n * @param {lunr.Token[]} tokens - All tokens for this document/field.\n * @returns {(?lunr.Token|lunr.Token[])}\n */\n\n/**\n * Register a function with the pipeline.\n *\n * Functions that are used in the pipeline should be registered if the pipeline\n * needs to be serialised, or a serialised pipeline needs to be loaded.\n *\n * Registering a function does not add it to a pipeline, functions must still be\n * added to instances of the pipeline for them to be used when running a pipeline.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @param {String} label - The label to register this function with\n */\nlunr.Pipeline.registerFunction = function (fn, label) {\n if (label in this.registeredFunctions) {\n lunr.utils.warn('Overwriting existing registered function: ' + label)\n }\n\n fn.label = label\n lunr.Pipeline.registeredFunctions[fn.label] = fn\n}\n\n/**\n * Warns if the function is not registered as a Pipeline function.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @private\n */\nlunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {\n var isRegistered = fn.label && (fn.label in this.registeredFunctions)\n\n if (!isRegistered) {\n lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\\n', fn)\n }\n}\n\n/**\n * Loads a previously serialised pipeline.\n *\n * All functions to be loaded must already be registered with lunr.Pipeline.\n * If any function from the serialised data has not been registered then an\n * error will be thrown.\n *\n * @param {Object} serialised - The serialised pipeline to load.\n * @returns {lunr.Pipeline}\n */\nlunr.Pipeline.load = function (serialised) {\n var pipeline = new lunr.Pipeline\n\n serialised.forEach(function (fnName) {\n var fn = lunr.Pipeline.registeredFunctions[fnName]\n\n if (fn) {\n pipeline.add(fn)\n } else {\n throw new Error('Cannot load unregistered function: ' + fnName)\n }\n })\n\n return pipeline\n}\n\n/**\n * Adds new functions to the end of the pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline.\n */\nlunr.Pipeline.prototype.add = function () {\n var fns = Array.prototype.slice.call(arguments)\n\n fns.forEach(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n this._stack.push(fn)\n }, this)\n}\n\n/**\n * Adds a single function after a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.after = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n pos = pos + 1\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Adds a single function before a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.before = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Removes a function from the pipeline.\n *\n * @param {lunr.PipelineFunction} fn The function to remove from the pipeline.\n */\nlunr.Pipeline.prototype.remove = function (fn) {\n var pos = this._stack.indexOf(fn)\n if (pos == -1) {\n return\n }\n\n this._stack.splice(pos, 1)\n}\n\n/**\n * Runs the current list of functions that make up the pipeline against the\n * passed tokens.\n *\n * @param {Array} tokens The tokens to run through the pipeline.\n * @returns {Array}\n */\nlunr.Pipeline.prototype.run = function (tokens) {\n var stackLength = this._stack.length\n\n for (var i = 0; i < stackLength; i++) {\n var fn = this._stack[i]\n var memo = []\n\n for (var j = 0; j < tokens.length; j++) {\n var result = fn(tokens[j], j, tokens)\n\n if (result === null || result === void 0 || result === '') continue\n\n if (Array.isArray(result)) {\n for (var k = 0; k < result.length; k++) {\n memo.push(result[k])\n }\n } else {\n memo.push(result)\n }\n }\n\n tokens = memo\n }\n\n return tokens\n}\n\n/**\n * Convenience method for passing a string through a pipeline and getting\n * strings out. This method takes care of wrapping the passed string in a\n * token and mapping the resulting tokens back to strings.\n *\n * @param {string} str - The string to pass through the pipeline.\n * @param {?object} metadata - Optional metadata to associate with the token\n * passed to the pipeline.\n * @returns {string[]}\n */\nlunr.Pipeline.prototype.runString = function (str, metadata) {\n var token = new lunr.Token (str, metadata)\n\n return this.run([token]).map(function (t) {\n return t.toString()\n })\n}\n\n/**\n * Resets the pipeline by removing any existing processors.\n *\n */\nlunr.Pipeline.prototype.reset = function () {\n this._stack = []\n}\n\n/**\n * Returns a representation of the pipeline ready for serialisation.\n *\n * Logs a warning if the function has not been registered.\n *\n * @returns {Array}\n */\nlunr.Pipeline.prototype.toJSON = function () {\n return this._stack.map(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n\n return fn.label\n })\n}\n/*!\n * lunr.Vector\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A vector is used to construct the vector space of documents and queries. These\n * vectors support operations to determine the similarity between two documents or\n * a document and a query.\n *\n * Normally no parameters are required for initializing a vector, but in the case of\n * loading a previously dumped vector the raw elements can be provided to the constructor.\n *\n * For performance reasons vectors are implemented with a flat array, where an elements\n * index is immediately followed by its value. E.g. [index, value, index, value]. This\n * allows the underlying array to be as sparse as possible and still offer decent\n * performance when being used for vector calculations.\n *\n * @constructor\n * @param {Number[]} [elements] - The flat list of element index and element value pairs.\n */\nlunr.Vector = function (elements) {\n this._magnitude = 0\n this.elements = elements || []\n}\n\n\n/**\n * Calculates the position within the vector to insert a given index.\n *\n * This is used internally by insert and upsert. If there are duplicate indexes then\n * the position is returned as if the value for that index were to be updated, but it\n * is the callers responsibility to check whether there is a duplicate at that index\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @returns {Number}\n */\nlunr.Vector.prototype.positionForIndex = function (index) {\n // For an empty vector the tuple can be inserted at the beginning\n if (this.elements.length == 0) {\n return 0\n }\n\n var start = 0,\n end = this.elements.length / 2,\n sliceLength = end - start,\n pivotPoint = Math.floor(sliceLength / 2),\n pivotIndex = this.elements[pivotPoint * 2]\n\n while (sliceLength > 1) {\n if (pivotIndex < index) {\n start = pivotPoint\n }\n\n if (pivotIndex > index) {\n end = pivotPoint\n }\n\n if (pivotIndex == index) {\n break\n }\n\n sliceLength = end - start\n pivotPoint = start + Math.floor(sliceLength / 2)\n pivotIndex = this.elements[pivotPoint * 2]\n }\n\n if (pivotIndex == index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex > index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex < index) {\n return (pivotPoint + 1) * 2\n }\n}\n\n/**\n * Inserts an element at an index within the vector.\n *\n * Does not allow duplicates, will throw an error if there is already an entry\n * for this index.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n */\nlunr.Vector.prototype.insert = function (insertIdx, val) {\n this.upsert(insertIdx, val, function () {\n throw \"duplicate index\"\n })\n}\n\n/**\n * Inserts or updates an existing index within the vector.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n * @param {function} fn - A function that is called for updates, the existing value and the\n * requested value are passed as arguments\n */\nlunr.Vector.prototype.upsert = function (insertIdx, val, fn) {\n this._magnitude = 0\n var position = this.positionForIndex(insertIdx)\n\n if (this.elements[position] == insertIdx) {\n this.elements[position + 1] = fn(this.elements[position + 1], val)\n } else {\n this.elements.splice(position, 0, insertIdx, val)\n }\n}\n\n/**\n * Calculates the magnitude of this vector.\n *\n * @returns {Number}\n */\nlunr.Vector.prototype.magnitude = function () {\n if (this._magnitude) return this._magnitude\n\n var sumOfSquares = 0,\n elementsLength = this.elements.length\n\n for (var i = 1; i < elementsLength; i += 2) {\n var val = this.elements[i]\n sumOfSquares += val * val\n }\n\n return this._magnitude = Math.sqrt(sumOfSquares)\n}\n\n/**\n * Calculates the dot product of this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The vector to compute the dot product with.\n * @returns {Number}\n */\nlunr.Vector.prototype.dot = function (otherVector) {\n var dotProduct = 0,\n a = this.elements, b = otherVector.elements,\n aLen = a.length, bLen = b.length,\n aVal = 0, bVal = 0,\n i = 0, j = 0\n\n while (i < aLen && j < bLen) {\n aVal = a[i], bVal = b[j]\n if (aVal < bVal) {\n i += 2\n } else if (aVal > bVal) {\n j += 2\n } else if (aVal == bVal) {\n dotProduct += a[i + 1] * b[j + 1]\n i += 2\n j += 2\n }\n }\n\n return dotProduct\n}\n\n/**\n * Calculates the similarity between this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The other vector to calculate the\n * similarity with.\n * @returns {Number}\n */\nlunr.Vector.prototype.similarity = function (otherVector) {\n return this.dot(otherVector) / this.magnitude() || 0\n}\n\n/**\n * Converts the vector to an array of the elements within the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toArray = function () {\n var output = new Array (this.elements.length / 2)\n\n for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) {\n output[j] = this.elements[i]\n }\n\n return output\n}\n\n/**\n * A JSON serializable representation of the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toJSON = function () {\n return this.elements\n}\n/* eslint-disable */\n/*!\n * lunr.stemmer\n * Copyright (C) 2020 Oliver Nightingale\n * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt\n */\n\n/**\n * lunr.stemmer is an english language stemmer, this is a JavaScript\n * implementation of the PorterStemmer taken from http://tartarus.org/~martin\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token - The string to stem\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n * @function\n */\nlunr.stemmer = (function(){\n var step2list = {\n \"ational\" : \"ate\",\n \"tional\" : \"tion\",\n \"enci\" : \"ence\",\n \"anci\" : \"ance\",\n \"izer\" : \"ize\",\n \"bli\" : \"ble\",\n \"alli\" : \"al\",\n \"entli\" : \"ent\",\n \"eli\" : \"e\",\n \"ousli\" : \"ous\",\n \"ization\" : \"ize\",\n \"ation\" : \"ate\",\n \"ator\" : \"ate\",\n \"alism\" : \"al\",\n \"iveness\" : \"ive\",\n \"fulness\" : \"ful\",\n \"ousness\" : \"ous\",\n \"aliti\" : \"al\",\n \"iviti\" : \"ive\",\n \"biliti\" : \"ble\",\n \"logi\" : \"log\"\n },\n\n step3list = {\n \"icate\" : \"ic\",\n \"ative\" : \"\",\n \"alize\" : \"al\",\n \"iciti\" : \"ic\",\n \"ical\" : \"ic\",\n \"ful\" : \"\",\n \"ness\" : \"\"\n },\n\n c = \"[^aeiou]\", // consonant\n v = \"[aeiouy]\", // vowel\n C = c + \"[^aeiouy]*\", // consonant sequence\n V = v + \"[aeiou]*\", // vowel sequence\n\n mgr0 = \"^(\" + C + \")?\" + V + C, // [C]VC... is m>0\n meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\", // [C]VC[V] is m=1\n mgr1 = \"^(\" + C + \")?\" + V + C + V + C, // [C]VCVC... is m>1\n s_v = \"^(\" + C + \")?\" + v; // vowel in stem\n\n var re_mgr0 = new RegExp(mgr0);\n var re_mgr1 = new RegExp(mgr1);\n var re_meq1 = new RegExp(meq1);\n var re_s_v = new RegExp(s_v);\n\n var re_1a = /^(.+?)(ss|i)es$/;\n var re2_1a = /^(.+?)([^s])s$/;\n var re_1b = /^(.+?)eed$/;\n var re2_1b = /^(.+?)(ed|ing)$/;\n var re_1b_2 = /.$/;\n var re2_1b_2 = /(at|bl|iz)$/;\n var re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n var re4_1b_2 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var re_1c = /^(.+?[^aeiou])y$/;\n var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n\n var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n\n var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n var re2_4 = /^(.+?)(s|t)(ion)$/;\n\n var re_5 = /^(.+?)e$/;\n var re_5_1 = /ll$/;\n var re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var porterStemmer = function porterStemmer(w) {\n var stem,\n suffix,\n firstch,\n re,\n re2,\n re3,\n re4;\n\n if (w.length < 3) { return w; }\n\n firstch = w.substr(0,1);\n if (firstch == \"y\") {\n w = firstch.toUpperCase() + w.substr(1);\n }\n\n // Step 1a\n re = re_1a\n re2 = re2_1a;\n\n if (re.test(w)) { w = w.replace(re,\"$1$2\"); }\n else if (re2.test(w)) { w = w.replace(re2,\"$1$2\"); }\n\n // Step 1b\n re = re_1b;\n re2 = re2_1b;\n if (re.test(w)) {\n var fp = re.exec(w);\n re = re_mgr0;\n if (re.test(fp[1])) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1];\n re2 = re_s_v;\n if (re2.test(stem)) {\n w = stem;\n re2 = re2_1b_2;\n re3 = re3_1b_2;\n re4 = re4_1b_2;\n if (re2.test(w)) { w = w + \"e\"; }\n else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,\"\"); }\n else if (re4.test(w)) { w = w + \"e\"; }\n }\n }\n\n // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n re = re_1c;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n w = stem + \"i\";\n }\n\n // Step 2\n re = re_2;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step2list[suffix];\n }\n }\n\n // Step 3\n re = re_3;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step3list[suffix];\n }\n }\n\n // Step 4\n re = re_4;\n re2 = re2_4;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n if (re.test(stem)) {\n w = stem;\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1] + fp[2];\n re2 = re_mgr1;\n if (re2.test(stem)) {\n w = stem;\n }\n }\n\n // Step 5\n re = re_5;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n re2 = re_meq1;\n re3 = re3_5;\n if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n w = stem;\n }\n }\n\n re = re_5_1;\n re2 = re_mgr1;\n if (re.test(w) && re2.test(w)) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n\n // and turn initial Y back to y\n\n if (firstch == \"y\") {\n w = firstch.toLowerCase() + w.substr(1);\n }\n\n return w;\n };\n\n return function (token) {\n return token.update(porterStemmer);\n }\n})();\n\nlunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')\n/*!\n * lunr.stopWordFilter\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.generateStopWordFilter builds a stopWordFilter function from the provided\n * list of stop words.\n *\n * The built in lunr.stopWordFilter is built using this generator and can be used\n * to generate custom stopWordFilters for applications or non English languages.\n *\n * @function\n * @param {Array} token The token to pass through the filter\n * @returns {lunr.PipelineFunction}\n * @see lunr.Pipeline\n * @see lunr.stopWordFilter\n */\nlunr.generateStopWordFilter = function (stopWords) {\n var words = stopWords.reduce(function (memo, stopWord) {\n memo[stopWord] = stopWord\n return memo\n }, {})\n\n return function (token) {\n if (token && words[token.toString()] !== token.toString()) return token\n }\n}\n\n/**\n * lunr.stopWordFilter is an English language stop word list filter, any words\n * contained in the list will not be passed through the filter.\n *\n * This is intended to be used in the Pipeline. If the token does not pass the\n * filter then undefined will be returned.\n *\n * @function\n * @implements {lunr.PipelineFunction}\n * @params {lunr.Token} token - A token to check for being a stop word.\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n */\nlunr.stopWordFilter = lunr.generateStopWordFilter([\n 'a',\n 'able',\n 'about',\n 'across',\n 'after',\n 'all',\n 'almost',\n 'also',\n 'am',\n 'among',\n 'an',\n 'and',\n 'any',\n 'are',\n 'as',\n 'at',\n 'be',\n 'because',\n 'been',\n 'but',\n 'by',\n 'can',\n 'cannot',\n 'could',\n 'dear',\n 'did',\n 'do',\n 'does',\n 'either',\n 'else',\n 'ever',\n 'every',\n 'for',\n 'from',\n 'get',\n 'got',\n 'had',\n 'has',\n 'have',\n 'he',\n 'her',\n 'hers',\n 'him',\n 'his',\n 'how',\n 'however',\n 'i',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'its',\n 'just',\n 'least',\n 'let',\n 'like',\n 'likely',\n 'may',\n 'me',\n 'might',\n 'most',\n 'must',\n 'my',\n 'neither',\n 'no',\n 'nor',\n 'not',\n 'of',\n 'off',\n 'often',\n 'on',\n 'only',\n 'or',\n 'other',\n 'our',\n 'own',\n 'rather',\n 'said',\n 'say',\n 'says',\n 'she',\n 'should',\n 'since',\n 'so',\n 'some',\n 'than',\n 'that',\n 'the',\n 'their',\n 'them',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'tis',\n 'to',\n 'too',\n 'twas',\n 'us',\n 'wants',\n 'was',\n 'we',\n 'were',\n 'what',\n 'when',\n 'where',\n 'which',\n 'while',\n 'who',\n 'whom',\n 'why',\n 'will',\n 'with',\n 'would',\n 'yet',\n 'you',\n 'your'\n])\n\nlunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')\n/*!\n * lunr.trimmer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.trimmer is a pipeline function for trimming non word\n * characters from the beginning and end of tokens before they\n * enter the index.\n *\n * This implementation may not work correctly for non latin\n * characters and should either be removed or adapted for use\n * with languages with non-latin characters.\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token The token to pass through the filter\n * @returns {lunr.Token}\n * @see lunr.Pipeline\n */\nlunr.trimmer = function (token) {\n return token.update(function (s) {\n return s.replace(/^\\W+/, '').replace(/\\W+$/, '')\n })\n}\n\nlunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')\n/*!\n * lunr.TokenSet\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A token set is used to store the unique list of all tokens\n * within an index. Token sets are also used to represent an\n * incoming query to the index, this query token set and index\n * token set are then intersected to find which tokens to look\n * up in the inverted index.\n *\n * A token set can hold multiple tokens, as in the case of the\n * index token set, or it can hold a single token as in the\n * case of a simple query token set.\n *\n * Additionally token sets are used to perform wildcard matching.\n * Leading, contained and trailing wildcards are supported, and\n * from this edit distance matching can also be provided.\n *\n * Token sets are implemented as a minimal finite state automata,\n * where both common prefixes and suffixes are shared between tokens.\n * This helps to reduce the space used for storing the token set.\n *\n * @constructor\n */\nlunr.TokenSet = function () {\n this.final = false\n this.edges = {}\n this.id = lunr.TokenSet._nextId\n lunr.TokenSet._nextId += 1\n}\n\n/**\n * Keeps track of the next, auto increment, identifier to assign\n * to a new tokenSet.\n *\n * TokenSets require a unique identifier to be correctly minimised.\n *\n * @private\n */\nlunr.TokenSet._nextId = 1\n\n/**\n * Creates a TokenSet instance from the given sorted array of words.\n *\n * @param {String[]} arr - A sorted array of strings to create the set from.\n * @returns {lunr.TokenSet}\n * @throws Will throw an error if the input array is not sorted.\n */\nlunr.TokenSet.fromArray = function (arr) {\n var builder = new lunr.TokenSet.Builder\n\n for (var i = 0, len = arr.length; i < len; i++) {\n builder.insert(arr[i])\n }\n\n builder.finish()\n return builder.root\n}\n\n/**\n * Creates a token set from a query clause.\n *\n * @private\n * @param {Object} clause - A single clause from lunr.Query.\n * @param {string} clause.term - The query clause term.\n * @param {number} [clause.editDistance] - The optional edit distance for the term.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromClause = function (clause) {\n if ('editDistance' in clause) {\n return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance)\n } else {\n return lunr.TokenSet.fromString(clause.term)\n }\n}\n\n/**\n * Creates a token set representing a single string with a specified\n * edit distance.\n *\n * Insertions, deletions, substitutions and transpositions are each\n * treated as an edit distance of 1.\n *\n * Increasing the allowed edit distance will have a dramatic impact\n * on the performance of both creating and intersecting these TokenSets.\n * It is advised to keep the edit distance less than 3.\n *\n * @param {string} str - The string to create the token set from.\n * @param {number} editDistance - The allowed edit distance to match.\n * @returns {lunr.Vector}\n */\nlunr.TokenSet.fromFuzzyString = function (str, editDistance) {\n var root = new lunr.TokenSet\n\n var stack = [{\n node: root,\n editsRemaining: editDistance,\n str: str\n }]\n\n while (stack.length) {\n var frame = stack.pop()\n\n // no edit\n if (frame.str.length > 0) {\n var char = frame.str.charAt(0),\n noEditNode\n\n if (char in frame.node.edges) {\n noEditNode = frame.node.edges[char]\n } else {\n noEditNode = new lunr.TokenSet\n frame.node.edges[char] = noEditNode\n }\n\n if (frame.str.length == 1) {\n noEditNode.final = true\n }\n\n stack.push({\n node: noEditNode,\n editsRemaining: frame.editsRemaining,\n str: frame.str.slice(1)\n })\n }\n\n if (frame.editsRemaining == 0) {\n continue\n }\n\n // insertion\n if (\"*\" in frame.node.edges) {\n var insertionNode = frame.node.edges[\"*\"]\n } else {\n var insertionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = insertionNode\n }\n\n if (frame.str.length == 0) {\n insertionNode.final = true\n }\n\n stack.push({\n node: insertionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str\n })\n\n // deletion\n // can only do a deletion if we have enough edits remaining\n // and if there are characters left to delete in the string\n if (frame.str.length > 1) {\n stack.push({\n node: frame.node,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // deletion\n // just removing the last character from the str\n if (frame.str.length == 1) {\n frame.node.final = true\n }\n\n // substitution\n // can only do a substitution if we have enough edits remaining\n // and if there are characters left to substitute\n if (frame.str.length >= 1) {\n if (\"*\" in frame.node.edges) {\n var substitutionNode = frame.node.edges[\"*\"]\n } else {\n var substitutionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = substitutionNode\n }\n\n if (frame.str.length == 1) {\n substitutionNode.final = true\n }\n\n stack.push({\n node: substitutionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // transposition\n // can only do a transposition if there are edits remaining\n // and there are enough characters to transpose\n if (frame.str.length > 1) {\n var charA = frame.str.charAt(0),\n charB = frame.str.charAt(1),\n transposeNode\n\n if (charB in frame.node.edges) {\n transposeNode = frame.node.edges[charB]\n } else {\n transposeNode = new lunr.TokenSet\n frame.node.edges[charB] = transposeNode\n }\n\n if (frame.str.length == 1) {\n transposeNode.final = true\n }\n\n stack.push({\n node: transposeNode,\n editsRemaining: frame.editsRemaining - 1,\n str: charA + frame.str.slice(2)\n })\n }\n }\n\n return root\n}\n\n/**\n * Creates a TokenSet from a string.\n *\n * The string may contain one or more wildcard characters (*)\n * that will allow wildcard matching when intersecting with\n * another TokenSet.\n *\n * @param {string} str - The string to create a TokenSet from.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromString = function (str) {\n var node = new lunr.TokenSet,\n root = node\n\n /*\n * Iterates through all characters within the passed string\n * appending a node for each character.\n *\n * When a wildcard character is found then a self\n * referencing edge is introduced to continually match\n * any number of any characters.\n */\n for (var i = 0, len = str.length; i < len; i++) {\n var char = str[i],\n final = (i == len - 1)\n\n if (char == \"*\") {\n node.edges[char] = node\n node.final = final\n\n } else {\n var next = new lunr.TokenSet\n next.final = final\n\n node.edges[char] = next\n node = next\n }\n }\n\n return root\n}\n\n/**\n * Converts this TokenSet into an array of strings\n * contained within the TokenSet.\n *\n * This is not intended to be used on a TokenSet that\n * contains wildcards, in these cases the results are\n * undefined and are likely to cause an infinite loop.\n *\n * @returns {string[]}\n */\nlunr.TokenSet.prototype.toArray = function () {\n var words = []\n\n var stack = [{\n prefix: \"\",\n node: this\n }]\n\n while (stack.length) {\n var frame = stack.pop(),\n edges = Object.keys(frame.node.edges),\n len = edges.length\n\n if (frame.node.final) {\n /* In Safari, at this point the prefix is sometimes corrupted, see:\n * https://github.com/olivernn/lunr.js/issues/279 Calling any\n * String.prototype method forces Safari to \"cast\" this string to what\n * it's supposed to be, fixing the bug. */\n frame.prefix.charAt(0)\n words.push(frame.prefix)\n }\n\n for (var i = 0; i < len; i++) {\n var edge = edges[i]\n\n stack.push({\n prefix: frame.prefix.concat(edge),\n node: frame.node.edges[edge]\n })\n }\n }\n\n return words\n}\n\n/**\n * Generates a string representation of a TokenSet.\n *\n * This is intended to allow TokenSets to be used as keys\n * in objects, largely to aid the construction and minimisation\n * of a TokenSet. As such it is not designed to be a human\n * friendly representation of the TokenSet.\n *\n * @returns {string}\n */\nlunr.TokenSet.prototype.toString = function () {\n // NOTE: Using Object.keys here as this.edges is very likely\n // to enter 'hash-mode' with many keys being added\n //\n // avoiding a for-in loop here as it leads to the function\n // being de-optimised (at least in V8). From some simple\n // benchmarks the performance is comparable, but allowing\n // V8 to optimize may mean easy performance wins in the future.\n\n if (this._str) {\n return this._str\n }\n\n var str = this.final ? '1' : '0',\n labels = Object.keys(this.edges).sort(),\n len = labels.length\n\n for (var i = 0; i < len; i++) {\n var label = labels[i],\n node = this.edges[label]\n\n str = str + label + node.id\n }\n\n return str\n}\n\n/**\n * Returns a new TokenSet that is the intersection of\n * this TokenSet and the passed TokenSet.\n *\n * This intersection will take into account any wildcards\n * contained within the TokenSet.\n *\n * @param {lunr.TokenSet} b - An other TokenSet to intersect with.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.prototype.intersect = function (b) {\n var output = new lunr.TokenSet,\n frame = undefined\n\n var stack = [{\n qNode: b,\n output: output,\n node: this\n }]\n\n while (stack.length) {\n frame = stack.pop()\n\n // NOTE: As with the #toString method, we are using\n // Object.keys and a for loop instead of a for-in loop\n // as both of these objects enter 'hash' mode, causing\n // the function to be de-optimised in V8\n var qEdges = Object.keys(frame.qNode.edges),\n qLen = qEdges.length,\n nEdges = Object.keys(frame.node.edges),\n nLen = nEdges.length\n\n for (var q = 0; q < qLen; q++) {\n var qEdge = qEdges[q]\n\n for (var n = 0; n < nLen; n++) {\n var nEdge = nEdges[n]\n\n if (nEdge == qEdge || qEdge == '*') {\n var node = frame.node.edges[nEdge],\n qNode = frame.qNode.edges[qEdge],\n final = node.final && qNode.final,\n next = undefined\n\n if (nEdge in frame.output.edges) {\n // an edge already exists for this character\n // no need to create a new node, just set the finality\n // bit unless this node is already final\n next = frame.output.edges[nEdge]\n next.final = next.final || final\n\n } else {\n // no edge exists yet, must create one\n // set the finality bit and insert it\n // into the output\n next = new lunr.TokenSet\n next.final = final\n frame.output.edges[nEdge] = next\n }\n\n stack.push({\n qNode: qNode,\n output: next,\n node: node\n })\n }\n }\n }\n }\n\n return output\n}\nlunr.TokenSet.Builder = function () {\n this.previousWord = \"\"\n this.root = new lunr.TokenSet\n this.uncheckedNodes = []\n this.minimizedNodes = {}\n}\n\nlunr.TokenSet.Builder.prototype.insert = function (word) {\n var node,\n commonPrefix = 0\n\n if (word < this.previousWord) {\n throw new Error (\"Out of order word insertion\")\n }\n\n for (var i = 0; i < word.length && i < this.previousWord.length; i++) {\n if (word[i] != this.previousWord[i]) break\n commonPrefix++\n }\n\n this.minimize(commonPrefix)\n\n if (this.uncheckedNodes.length == 0) {\n node = this.root\n } else {\n node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child\n }\n\n for (var i = commonPrefix; i < word.length; i++) {\n var nextNode = new lunr.TokenSet,\n char = word[i]\n\n node.edges[char] = nextNode\n\n this.uncheckedNodes.push({\n parent: node,\n char: char,\n child: nextNode\n })\n\n node = nextNode\n }\n\n node.final = true\n this.previousWord = word\n}\n\nlunr.TokenSet.Builder.prototype.finish = function () {\n this.minimize(0)\n}\n\nlunr.TokenSet.Builder.prototype.minimize = function (downTo) {\n for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) {\n var node = this.uncheckedNodes[i],\n childKey = node.child.toString()\n\n if (childKey in this.minimizedNodes) {\n node.parent.edges[node.char] = this.minimizedNodes[childKey]\n } else {\n // Cache the key for this node since\n // we know it can't change anymore\n node.child._str = childKey\n\n this.minimizedNodes[childKey] = node.child\n }\n\n this.uncheckedNodes.pop()\n }\n}\n/*!\n * lunr.Index\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * An index contains the built index of all documents and provides a query interface\n * to the index.\n *\n * Usually instances of lunr.Index will not be created using this constructor, instead\n * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be\n * used to load previously built and serialized indexes.\n *\n * @constructor\n * @param {Object} attrs - The attributes of the built search index.\n * @param {Object} attrs.invertedIndex - An index of term/field to document reference.\n * @param {Object} attrs.fieldVectors - Field vectors\n * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens.\n * @param {string[]} attrs.fields - The names of indexed document fields.\n * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms.\n */\nlunr.Index = function (attrs) {\n this.invertedIndex = attrs.invertedIndex\n this.fieldVectors = attrs.fieldVectors\n this.tokenSet = attrs.tokenSet\n this.fields = attrs.fields\n this.pipeline = attrs.pipeline\n}\n\n/**\n * A result contains details of a document matching a search query.\n * @typedef {Object} lunr.Index~Result\n * @property {string} ref - The reference of the document this result represents.\n * @property {number} score - A number between 0 and 1 representing how similar this document is to the query.\n * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match.\n */\n\n/**\n * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple\n * query language which itself is parsed into an instance of lunr.Query.\n *\n * For programmatically building queries it is advised to directly use lunr.Query, the query language\n * is best used for human entered text rather than program generated text.\n *\n * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported\n * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello'\n * or 'world', though those that contain both will rank higher in the results.\n *\n * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can\n * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding\n * wildcards will increase the number of documents that will be found but can also have a negative\n * impact on query performance, especially with wildcards at the beginning of a term.\n *\n * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term\n * hello in the title field will match this query. Using a field not present in the index will lead\n * to an error being thrown.\n *\n * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term\n * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported\n * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2.\n * Avoid large values for edit distance to improve query performance.\n *\n * Each term also supports a presence modifier. By default a term's presence in document is optional, however\n * this can be changed to either required or prohibited. For a term's presence to be required in a document the\n * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and\n * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not\n * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'.\n *\n * To escape special characters the backslash character '\\' can be used, this allows searches to include\n * characters that would normally be considered modifiers, e.g. `foo\\~2` will search for a term \"foo~2\" instead\n * of attempting to apply a boost of 2 to the search term \"foo\".\n *\n * @typedef {string} lunr.Index~QueryString\n * @example Simple single term query\n * hello\n * @example Multiple term query\n * hello world\n * @example term scoped to a field\n * title:hello\n * @example term with a boost of 10\n * hello^10\n * @example term with an edit distance of 2\n * hello~2\n * @example terms with presence modifiers\n * -foo +bar baz\n */\n\n/**\n * Performs a search against the index using lunr query syntax.\n *\n * Results will be returned sorted by their score, the most relevant results\n * will be returned first. For details on how the score is calculated, please see\n * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}.\n *\n * For more programmatic querying use lunr.Index#query.\n *\n * @param {lunr.Index~QueryString} queryString - A string containing a lunr query.\n * @throws {lunr.QueryParseError} If the passed query string cannot be parsed.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.search = function (queryString) {\n return this.query(function (query) {\n var parser = new lunr.QueryParser(queryString, query)\n parser.parse()\n })\n}\n\n/**\n * A query builder callback provides a query object to be used to express\n * the query to perform on the index.\n *\n * @callback lunr.Index~queryBuilder\n * @param {lunr.Query} query - The query object to build up.\n * @this lunr.Query\n */\n\n/**\n * Performs a query against the index using the yielded lunr.Query object.\n *\n * If performing programmatic queries against the index, this method is preferred\n * over lunr.Index#search so as to avoid the additional query parsing overhead.\n *\n * A query object is yielded to the supplied function which should be used to\n * express the query to be run against the index.\n *\n * Note that although this function takes a callback parameter it is _not_ an\n * asynchronous operation, the callback is just yielded a query object to be\n * customized.\n *\n * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.query = function (fn) {\n // for each query clause\n // * process terms\n // * expand terms from token set\n // * find matching documents and metadata\n // * get document vectors\n // * score documents\n\n var query = new lunr.Query(this.fields),\n matchingFields = Object.create(null),\n queryVectors = Object.create(null),\n termFieldCache = Object.create(null),\n requiredMatches = Object.create(null),\n prohibitedMatches = Object.create(null)\n\n /*\n * To support field level boosts a query vector is created per\n * field. An empty vector is eagerly created to support negated\n * queries.\n */\n for (var i = 0; i < this.fields.length; i++) {\n queryVectors[this.fields[i]] = new lunr.Vector\n }\n\n fn.call(query, query)\n\n for (var i = 0; i < query.clauses.length; i++) {\n /*\n * Unless the pipeline has been disabled for this term, which is\n * the case for terms with wildcards, we need to pass the clause\n * term through the search pipeline. A pipeline returns an array\n * of processed terms. Pipeline functions may expand the passed\n * term, which means we may end up performing multiple index lookups\n * for a single query term.\n */\n var clause = query.clauses[i],\n terms = null,\n clauseMatches = lunr.Set.empty\n\n if (clause.usePipeline) {\n terms = this.pipeline.runString(clause.term, {\n fields: clause.fields\n })\n } else {\n terms = [clause.term]\n }\n\n for (var m = 0; m < terms.length; m++) {\n var term = terms[m]\n\n /*\n * Each term returned from the pipeline needs to use the same query\n * clause object, e.g. the same boost and or edit distance. The\n * simplest way to do this is to re-use the clause object but mutate\n * its term property.\n */\n clause.term = term\n\n /*\n * From the term in the clause we create a token set which will then\n * be used to intersect the indexes token set to get a list of terms\n * to lookup in the inverted index\n */\n var termTokenSet = lunr.TokenSet.fromClause(clause),\n expandedTerms = this.tokenSet.intersect(termTokenSet).toArray()\n\n /*\n * If a term marked as required does not exist in the tokenSet it is\n * impossible for the search to return any matches. We set all the field\n * scoped required matches set to empty and stop examining any further\n * clauses.\n */\n if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = lunr.Set.empty\n }\n\n break\n }\n\n for (var j = 0; j < expandedTerms.length; j++) {\n /*\n * For each term get the posting and termIndex, this is required for\n * building the query vector.\n */\n var expandedTerm = expandedTerms[j],\n posting = this.invertedIndex[expandedTerm],\n termIndex = posting._index\n\n for (var k = 0; k < clause.fields.length; k++) {\n /*\n * For each field that this query term is scoped by (by default\n * all fields are in scope) we need to get all the document refs\n * that have this term in that field.\n *\n * The posting is the entry in the invertedIndex for the matching\n * term from above.\n */\n var field = clause.fields[k],\n fieldPosting = posting[field],\n matchingDocumentRefs = Object.keys(fieldPosting),\n termField = expandedTerm + \"/\" + field,\n matchingDocumentsSet = new lunr.Set(matchingDocumentRefs)\n\n /*\n * if the presence of this term is required ensure that the matching\n * documents are added to the set of required matches for this clause.\n *\n */\n if (clause.presence == lunr.Query.presence.REQUIRED) {\n clauseMatches = clauseMatches.union(matchingDocumentsSet)\n\n if (requiredMatches[field] === undefined) {\n requiredMatches[field] = lunr.Set.complete\n }\n }\n\n /*\n * if the presence of this term is prohibited ensure that the matching\n * documents are added to the set of prohibited matches for this field,\n * creating that set if it does not yet exist.\n */\n if (clause.presence == lunr.Query.presence.PROHIBITED) {\n if (prohibitedMatches[field] === undefined) {\n prohibitedMatches[field] = lunr.Set.empty\n }\n\n prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet)\n\n /*\n * Prohibited matches should not be part of the query vector used for\n * similarity scoring and no metadata should be extracted so we continue\n * to the next field\n */\n continue\n }\n\n /*\n * The query field vector is populated using the termIndex found for\n * the term and a unit value with the appropriate boost applied.\n * Using upsert because there could already be an entry in the vector\n * for the term we are working with. In that case we just add the scores\n * together.\n */\n queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b })\n\n /**\n * If we've already seen this term, field combo then we've already collected\n * the matching documents and metadata, no need to go through all that again\n */\n if (termFieldCache[termField]) {\n continue\n }\n\n for (var l = 0; l < matchingDocumentRefs.length; l++) {\n /*\n * All metadata for this term/field/document triple\n * are then extracted and collected into an instance\n * of lunr.MatchData ready to be returned in the query\n * results\n */\n var matchingDocumentRef = matchingDocumentRefs[l],\n matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field),\n metadata = fieldPosting[matchingDocumentRef],\n fieldMatch\n\n if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) {\n matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata)\n } else {\n fieldMatch.add(expandedTerm, field, metadata)\n }\n\n }\n\n termFieldCache[termField] = true\n }\n }\n }\n\n /**\n * If the presence was required we need to update the requiredMatches field sets.\n * We do this after all fields for the term have collected their matches because\n * the clause terms presence is required in _any_ of the fields not _all_ of the\n * fields.\n */\n if (clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = requiredMatches[field].intersect(clauseMatches)\n }\n }\n }\n\n /**\n * Need to combine the field scoped required and prohibited\n * matching documents into a global set of required and prohibited\n * matches\n */\n var allRequiredMatches = lunr.Set.complete,\n allProhibitedMatches = lunr.Set.empty\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i]\n\n if (requiredMatches[field]) {\n allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field])\n }\n\n if (prohibitedMatches[field]) {\n allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field])\n }\n }\n\n var matchingFieldRefs = Object.keys(matchingFields),\n results = [],\n matches = Object.create(null)\n\n /*\n * If the query is negated (contains only prohibited terms)\n * we need to get _all_ fieldRefs currently existing in the\n * index. This is only done when we know that the query is\n * entirely prohibited terms to avoid any cost of getting all\n * fieldRefs unnecessarily.\n *\n * Additionally, blank MatchData must be created to correctly\n * populate the results.\n */\n if (query.isNegated()) {\n matchingFieldRefs = Object.keys(this.fieldVectors)\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n var matchingFieldRef = matchingFieldRefs[i]\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRef)\n matchingFields[matchingFieldRef] = new lunr.MatchData\n }\n }\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n /*\n * Currently we have document fields that match the query, but we\n * need to return documents. The matchData and scores are combined\n * from multiple fields belonging to the same document.\n *\n * Scores are calculated by field, using the query vectors created\n * above, and combined into a final document score using addition.\n */\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]),\n docRef = fieldRef.docRef\n\n if (!allRequiredMatches.contains(docRef)) {\n continue\n }\n\n if (allProhibitedMatches.contains(docRef)) {\n continue\n }\n\n var fieldVector = this.fieldVectors[fieldRef],\n score = queryVectors[fieldRef.fieldName].similarity(fieldVector),\n docMatch\n\n if ((docMatch = matches[docRef]) !== undefined) {\n docMatch.score += score\n docMatch.matchData.combine(matchingFields[fieldRef])\n } else {\n var match = {\n ref: docRef,\n score: score,\n matchData: matchingFields[fieldRef]\n }\n matches[docRef] = match\n results.push(match)\n }\n }\n\n /*\n * Sort the results objects by score, highest first.\n */\n return results.sort(function (a, b) {\n return b.score - a.score\n })\n}\n\n/**\n * Prepares the index for JSON serialization.\n *\n * The schema for this JSON blob will be described in a\n * separate JSON schema file.\n *\n * @returns {Object}\n */\nlunr.Index.prototype.toJSON = function () {\n var invertedIndex = Object.keys(this.invertedIndex)\n .sort()\n .map(function (term) {\n return [term, this.invertedIndex[term]]\n }, this)\n\n var fieldVectors = Object.keys(this.fieldVectors)\n .map(function (ref) {\n return [ref, this.fieldVectors[ref].toJSON()]\n }, this)\n\n return {\n version: lunr.version,\n fields: this.fields,\n fieldVectors: fieldVectors,\n invertedIndex: invertedIndex,\n pipeline: this.pipeline.toJSON()\n }\n}\n\n/**\n * Loads a previously serialized lunr.Index\n *\n * @param {Object} serializedIndex - A previously serialized lunr.Index\n * @returns {lunr.Index}\n */\nlunr.Index.load = function (serializedIndex) {\n var attrs = {},\n fieldVectors = {},\n serializedVectors = serializedIndex.fieldVectors,\n invertedIndex = Object.create(null),\n serializedInvertedIndex = serializedIndex.invertedIndex,\n tokenSetBuilder = new lunr.TokenSet.Builder,\n pipeline = lunr.Pipeline.load(serializedIndex.pipeline)\n\n if (serializedIndex.version != lunr.version) {\n lunr.utils.warn(\"Version mismatch when loading serialised index. Current version of lunr '\" + lunr.version + \"' does not match serialized index '\" + serializedIndex.version + \"'\")\n }\n\n for (var i = 0; i < serializedVectors.length; i++) {\n var tuple = serializedVectors[i],\n ref = tuple[0],\n elements = tuple[1]\n\n fieldVectors[ref] = new lunr.Vector(elements)\n }\n\n for (var i = 0; i < serializedInvertedIndex.length; i++) {\n var tuple = serializedInvertedIndex[i],\n term = tuple[0],\n posting = tuple[1]\n\n tokenSetBuilder.insert(term)\n invertedIndex[term] = posting\n }\n\n tokenSetBuilder.finish()\n\n attrs.fields = serializedIndex.fields\n\n attrs.fieldVectors = fieldVectors\n attrs.invertedIndex = invertedIndex\n attrs.tokenSet = tokenSetBuilder.root\n attrs.pipeline = pipeline\n\n return new lunr.Index(attrs)\n}\n/*!\n * lunr.Builder\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Builder performs indexing on a set of documents and\n * returns instances of lunr.Index ready for querying.\n *\n * All configuration of the index is done via the builder, the\n * fields to index, the document reference, the text processing\n * pipeline and document scoring parameters are all set on the\n * builder before indexing.\n *\n * @constructor\n * @property {string} _ref - Internal reference to the document reference field.\n * @property {string[]} _fields - Internal reference to the document fields to index.\n * @property {object} invertedIndex - The inverted index maps terms to document fields.\n * @property {object} documentTermFrequencies - Keeps track of document term frequencies.\n * @property {object} documentLengths - Keeps track of the length of documents added to the index.\n * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing.\n * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing.\n * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index.\n * @property {number} documentCount - Keeps track of the total number of documents indexed.\n * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75.\n * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2.\n * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space.\n * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index.\n */\nlunr.Builder = function () {\n this._ref = \"id\"\n this._fields = Object.create(null)\n this._documents = Object.create(null)\n this.invertedIndex = Object.create(null)\n this.fieldTermFrequencies = {}\n this.fieldLengths = {}\n this.tokenizer = lunr.tokenizer\n this.pipeline = new lunr.Pipeline\n this.searchPipeline = new lunr.Pipeline\n this.documentCount = 0\n this._b = 0.75\n this._k1 = 1.2\n this.termIndex = 0\n this.metadataWhitelist = []\n}\n\n/**\n * Sets the document field used as the document reference. Every document must have this field.\n * The type of this field in the document should be a string, if it is not a string it will be\n * coerced into a string by calling toString.\n *\n * The default ref is 'id'.\n *\n * The ref should _not_ be changed during indexing, it should be set before any documents are\n * added to the index. Changing it during indexing can lead to inconsistent results.\n *\n * @param {string} ref - The name of the reference field in the document.\n */\nlunr.Builder.prototype.ref = function (ref) {\n this._ref = ref\n}\n\n/**\n * A function that is used to extract a field from a document.\n *\n * Lunr expects a field to be at the top level of a document, if however the field\n * is deeply nested within a document an extractor function can be used to extract\n * the right field for indexing.\n *\n * @callback fieldExtractor\n * @param {object} doc - The document being added to the index.\n * @returns {?(string|object|object[])} obj - The object that will be indexed for this field.\n * @example Extracting a nested field\n * function (doc) { return doc.nested.field }\n */\n\n/**\n * Adds a field to the list of document fields that will be indexed. Every document being\n * indexed should have this field. Null values for this field in indexed documents will\n * not cause errors but will limit the chance of that document being retrieved by searches.\n *\n * All fields should be added before adding documents to the index. Adding fields after\n * a document has been indexed will have no effect on already indexed documents.\n *\n * Fields can be boosted at build time. This allows terms within that field to have more\n * importance when ranking search results. Use a field boost to specify that matches within\n * one field are more important than other fields.\n *\n * @param {string} fieldName - The name of a field to index in all documents.\n * @param {object} attributes - Optional attributes associated with this field.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this field.\n * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document.\n * @throws {RangeError} fieldName cannot contain unsupported characters '/'\n */\nlunr.Builder.prototype.field = function (fieldName, attributes) {\n if (/\\//.test(fieldName)) {\n throw new RangeError (\"Field '\" + fieldName + \"' contains illegal character '/'\")\n }\n\n this._fields[fieldName] = attributes || {}\n}\n\n/**\n * A parameter to tune the amount of field length normalisation that is applied when\n * calculating relevance scores. A value of 0 will completely disable any normalisation\n * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b\n * will be clamped to the range 0 - 1.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.b = function (number) {\n if (number < 0) {\n this._b = 0\n } else if (number > 1) {\n this._b = 1\n } else {\n this._b = number\n }\n}\n\n/**\n * A parameter that controls the speed at which a rise in term frequency results in term\n * frequency saturation. The default value is 1.2. Setting this to a higher value will give\n * slower saturation levels, a lower value will result in quicker saturation.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.k1 = function (number) {\n this._k1 = number\n}\n\n/**\n * Adds a document to the index.\n *\n * Before adding fields to the index the index should have been fully setup, with the document\n * ref and all fields to index already having been specified.\n *\n * The document must have a field name as specified by the ref (by default this is 'id') and\n * it should have all fields defined for indexing, though null or undefined values will not\n * cause errors.\n *\n * Entire documents can be boosted at build time. Applying a boost to a document indicates that\n * this document should rank higher in search results than other documents.\n *\n * @param {object} doc - The document to add to the index.\n * @param {object} attributes - Optional attributes associated with this document.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this document.\n */\nlunr.Builder.prototype.add = function (doc, attributes) {\n var docRef = doc[this._ref],\n fields = Object.keys(this._fields)\n\n this._documents[docRef] = attributes || {}\n this.documentCount += 1\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i],\n extractor = this._fields[fieldName].extractor,\n field = extractor ? extractor(doc) : doc[fieldName],\n tokens = this.tokenizer(field, {\n fields: [fieldName]\n }),\n terms = this.pipeline.run(tokens),\n fieldRef = new lunr.FieldRef (docRef, fieldName),\n fieldTerms = Object.create(null)\n\n this.fieldTermFrequencies[fieldRef] = fieldTerms\n this.fieldLengths[fieldRef] = 0\n\n // store the length of this field for this document\n this.fieldLengths[fieldRef] += terms.length\n\n // calculate term frequencies for this field\n for (var j = 0; j < terms.length; j++) {\n var term = terms[j]\n\n if (fieldTerms[term] == undefined) {\n fieldTerms[term] = 0\n }\n\n fieldTerms[term] += 1\n\n // add to inverted index\n // create an initial posting if one doesn't exist\n if (this.invertedIndex[term] == undefined) {\n var posting = Object.create(null)\n posting[\"_index\"] = this.termIndex\n this.termIndex += 1\n\n for (var k = 0; k < fields.length; k++) {\n posting[fields[k]] = Object.create(null)\n }\n\n this.invertedIndex[term] = posting\n }\n\n // add an entry for this term/fieldName/docRef to the invertedIndex\n if (this.invertedIndex[term][fieldName][docRef] == undefined) {\n this.invertedIndex[term][fieldName][docRef] = Object.create(null)\n }\n\n // store all whitelisted metadata about this token in the\n // inverted index\n for (var l = 0; l < this.metadataWhitelist.length; l++) {\n var metadataKey = this.metadataWhitelist[l],\n metadata = term.metadata[metadataKey]\n\n if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) {\n this.invertedIndex[term][fieldName][docRef][metadataKey] = []\n }\n\n this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata)\n }\n }\n\n }\n}\n\n/**\n * Calculates the average document length for this index\n *\n * @private\n */\nlunr.Builder.prototype.calculateAverageFieldLengths = function () {\n\n var fieldRefs = Object.keys(this.fieldLengths),\n numberOfFields = fieldRefs.length,\n accumulator = {},\n documentsWithField = {}\n\n for (var i = 0; i < numberOfFields; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n field = fieldRef.fieldName\n\n documentsWithField[field] || (documentsWithField[field] = 0)\n documentsWithField[field] += 1\n\n accumulator[field] || (accumulator[field] = 0)\n accumulator[field] += this.fieldLengths[fieldRef]\n }\n\n var fields = Object.keys(this._fields)\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i]\n accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName]\n }\n\n this.averageFieldLength = accumulator\n}\n\n/**\n * Builds a vector space model of every document using lunr.Vector\n *\n * @private\n */\nlunr.Builder.prototype.createFieldVectors = function () {\n var fieldVectors = {},\n fieldRefs = Object.keys(this.fieldTermFrequencies),\n fieldRefsLength = fieldRefs.length,\n termIdfCache = Object.create(null)\n\n for (var i = 0; i < fieldRefsLength; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n fieldName = fieldRef.fieldName,\n fieldLength = this.fieldLengths[fieldRef],\n fieldVector = new lunr.Vector,\n termFrequencies = this.fieldTermFrequencies[fieldRef],\n terms = Object.keys(termFrequencies),\n termsLength = terms.length\n\n\n var fieldBoost = this._fields[fieldName].boost || 1,\n docBoost = this._documents[fieldRef.docRef].boost || 1\n\n for (var j = 0; j < termsLength; j++) {\n var term = terms[j],\n tf = termFrequencies[term],\n termIndex = this.invertedIndex[term]._index,\n idf, score, scoreWithPrecision\n\n if (termIdfCache[term] === undefined) {\n idf = lunr.idf(this.invertedIndex[term], this.documentCount)\n termIdfCache[term] = idf\n } else {\n idf = termIdfCache[term]\n }\n\n score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf)\n score *= fieldBoost\n score *= docBoost\n scoreWithPrecision = Math.round(score * 1000) / 1000\n // Converts 1.23456789 to 1.234.\n // Reducing the precision so that the vectors take up less\n // space when serialised. Doing it now so that they behave\n // the same before and after serialisation. Also, this is\n // the fastest approach to reducing a number's precision in\n // JavaScript.\n\n fieldVector.insert(termIndex, scoreWithPrecision)\n }\n\n fieldVectors[fieldRef] = fieldVector\n }\n\n this.fieldVectors = fieldVectors\n}\n\n/**\n * Creates a token set of all tokens in the index using lunr.TokenSet\n *\n * @private\n */\nlunr.Builder.prototype.createTokenSet = function () {\n this.tokenSet = lunr.TokenSet.fromArray(\n Object.keys(this.invertedIndex).sort()\n )\n}\n\n/**\n * Builds the index, creating an instance of lunr.Index.\n *\n * This completes the indexing process and should only be called\n * once all documents have been added to the index.\n *\n * @returns {lunr.Index}\n */\nlunr.Builder.prototype.build = function () {\n this.calculateAverageFieldLengths()\n this.createFieldVectors()\n this.createTokenSet()\n\n return new lunr.Index({\n invertedIndex: this.invertedIndex,\n fieldVectors: this.fieldVectors,\n tokenSet: this.tokenSet,\n fields: Object.keys(this._fields),\n pipeline: this.searchPipeline\n })\n}\n\n/**\n * Applies a plugin to the index builder.\n *\n * A plugin is a function that is called with the index builder as its context.\n * Plugins can be used to customise or extend the behaviour of the index\n * in some way. A plugin is just a function, that encapsulated the custom\n * behaviour that should be applied when building the index.\n *\n * The plugin function will be called with the index builder as its argument, additional\n * arguments can also be passed when calling use. The function will be called\n * with the index builder as its context.\n *\n * @param {Function} plugin The plugin to apply.\n */\nlunr.Builder.prototype.use = function (fn) {\n var args = Array.prototype.slice.call(arguments, 1)\n args.unshift(this)\n fn.apply(this, args)\n}\n/**\n * Contains and collects metadata about a matching document.\n * A single instance of lunr.MatchData is returned as part of every\n * lunr.Index~Result.\n *\n * @constructor\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n * @property {object} metadata - A cloned collection of metadata associated with this document.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData = function (term, field, metadata) {\n var clonedMetadata = Object.create(null),\n metadataKeys = Object.keys(metadata || {})\n\n // Cloning the metadata to prevent the original\n // being mutated during match data combination.\n // Metadata is kept in an array within the inverted\n // index so cloning the data can be done with\n // Array#slice\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n clonedMetadata[key] = metadata[key].slice()\n }\n\n this.metadata = Object.create(null)\n\n if (term !== undefined) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = clonedMetadata\n }\n}\n\n/**\n * An instance of lunr.MatchData will be created for every term that matches a\n * document. However only one instance is required in a lunr.Index~Result. This\n * method combines metadata from another instance of lunr.MatchData with this\n * objects metadata.\n *\n * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData.prototype.combine = function (otherMatchData) {\n var terms = Object.keys(otherMatchData.metadata)\n\n for (var i = 0; i < terms.length; i++) {\n var term = terms[i],\n fields = Object.keys(otherMatchData.metadata[term])\n\n if (this.metadata[term] == undefined) {\n this.metadata[term] = Object.create(null)\n }\n\n for (var j = 0; j < fields.length; j++) {\n var field = fields[j],\n keys = Object.keys(otherMatchData.metadata[term][field])\n\n if (this.metadata[term][field] == undefined) {\n this.metadata[term][field] = Object.create(null)\n }\n\n for (var k = 0; k < keys.length; k++) {\n var key = keys[k]\n\n if (this.metadata[term][field][key] == undefined) {\n this.metadata[term][field][key] = otherMatchData.metadata[term][field][key]\n } else {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key])\n }\n\n }\n }\n }\n}\n\n/**\n * Add metadata for a term/field pair to this instance of match data.\n *\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n */\nlunr.MatchData.prototype.add = function (term, field, metadata) {\n if (!(term in this.metadata)) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = metadata\n return\n }\n\n if (!(field in this.metadata[term])) {\n this.metadata[term][field] = metadata\n return\n }\n\n var metadataKeys = Object.keys(metadata)\n\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n\n if (key in this.metadata[term][field]) {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key])\n } else {\n this.metadata[term][field][key] = metadata[key]\n }\n }\n}\n/**\n * A lunr.Query provides a programmatic way of defining queries to be performed\n * against a {@link lunr.Index}.\n *\n * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method\n * so the query object is pre-initialized with the right index fields.\n *\n * @constructor\n * @property {lunr.Query~Clause[]} clauses - An array of query clauses.\n * @property {string[]} allFields - An array of all available fields in a lunr.Index.\n */\nlunr.Query = function (allFields) {\n this.clauses = []\n this.allFields = allFields\n}\n\n/**\n * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause.\n *\n * This allows wildcards to be added to the beginning and end of a term without having to manually do any string\n * concatenation.\n *\n * The wildcard constants can be bitwise combined to select both leading and trailing wildcards.\n *\n * @constant\n * @default\n * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour\n * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists\n * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with trailing wildcard\n * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING })\n * @example query term with leading and trailing wildcard\n * query.term('foo', {\n * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING\n * })\n */\n\nlunr.Query.wildcard = new String (\"*\")\nlunr.Query.wildcard.NONE = 0\nlunr.Query.wildcard.LEADING = 1\nlunr.Query.wildcard.TRAILING = 2\n\n/**\n * Constants for indicating what kind of presence a term must have in matching documents.\n *\n * @constant\n * @enum {number}\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with required presence\n * query.term('foo', { presence: lunr.Query.presence.REQUIRED })\n */\nlunr.Query.presence = {\n /**\n * Term's presence in a document is optional, this is the default value.\n */\n OPTIONAL: 1,\n\n /**\n * Term's presence in a document is required, documents that do not contain\n * this term will not be returned.\n */\n REQUIRED: 2,\n\n /**\n * Term's presence in a document is prohibited, documents that do contain\n * this term will not be returned.\n */\n PROHIBITED: 3\n}\n\n/**\n * A single clause in a {@link lunr.Query} contains a term and details on how to\n * match that term against a {@link lunr.Index}.\n *\n * @typedef {Object} lunr.Query~Clause\n * @property {string[]} fields - The fields in an index this clause should be matched against.\n * @property {number} [boost=1] - Any boost that should be applied when matching this clause.\n * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be.\n * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline.\n * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended.\n * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents.\n */\n\n/**\n * Adds a {@link lunr.Query~Clause} to this query.\n *\n * Unless the clause contains the fields to be matched all fields will be matched. In addition\n * a default boost of 1 is applied to the clause.\n *\n * @param {lunr.Query~Clause} clause - The clause to add to this query.\n * @see lunr.Query~Clause\n * @returns {lunr.Query}\n */\nlunr.Query.prototype.clause = function (clause) {\n if (!('fields' in clause)) {\n clause.fields = this.allFields\n }\n\n if (!('boost' in clause)) {\n clause.boost = 1\n }\n\n if (!('usePipeline' in clause)) {\n clause.usePipeline = true\n }\n\n if (!('wildcard' in clause)) {\n clause.wildcard = lunr.Query.wildcard.NONE\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) {\n clause.term = \"*\" + clause.term\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) {\n clause.term = \"\" + clause.term + \"*\"\n }\n\n if (!('presence' in clause)) {\n clause.presence = lunr.Query.presence.OPTIONAL\n }\n\n this.clauses.push(clause)\n\n return this\n}\n\n/**\n * A negated query is one in which every clause has a presence of\n * prohibited. These queries require some special processing to return\n * the expected results.\n *\n * @returns boolean\n */\nlunr.Query.prototype.isNegated = function () {\n for (var i = 0; i < this.clauses.length; i++) {\n if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause}\n * to the list of clauses that make up this query.\n *\n * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion\n * to a token or token-like string should be done before calling this method.\n *\n * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an\n * array, each term in the array will share the same options.\n *\n * @param {object|object[]} term - The term(s) to add to the query.\n * @param {object} [options] - Any additional properties to add to the query clause.\n * @returns {lunr.Query}\n * @see lunr.Query#clause\n * @see lunr.Query~Clause\n * @example adding a single term to a query\n * query.term(\"foo\")\n * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard\n * query.term(\"foo\", {\n * fields: [\"title\"],\n * boost: 10,\n * wildcard: lunr.Query.wildcard.TRAILING\n * })\n * @example using lunr.tokenizer to convert a string to tokens before using them as terms\n * query.term(lunr.tokenizer(\"foo bar\"))\n */\nlunr.Query.prototype.term = function (term, options) {\n if (Array.isArray(term)) {\n term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this)\n return this\n }\n\n var clause = options || {}\n clause.term = term.toString()\n\n this.clause(clause)\n\n return this\n}\nlunr.QueryParseError = function (message, start, end) {\n this.name = \"QueryParseError\"\n this.message = message\n this.start = start\n this.end = end\n}\n\nlunr.QueryParseError.prototype = new Error\nlunr.QueryLexer = function (str) {\n this.lexemes = []\n this.str = str\n this.length = str.length\n this.pos = 0\n this.start = 0\n this.escapeCharPositions = []\n}\n\nlunr.QueryLexer.prototype.run = function () {\n var state = lunr.QueryLexer.lexText\n\n while (state) {\n state = state(this)\n }\n}\n\nlunr.QueryLexer.prototype.sliceString = function () {\n var subSlices = [],\n sliceStart = this.start,\n sliceEnd = this.pos\n\n for (var i = 0; i < this.escapeCharPositions.length; i++) {\n sliceEnd = this.escapeCharPositions[i]\n subSlices.push(this.str.slice(sliceStart, sliceEnd))\n sliceStart = sliceEnd + 1\n }\n\n subSlices.push(this.str.slice(sliceStart, this.pos))\n this.escapeCharPositions.length = 0\n\n return subSlices.join('')\n}\n\nlunr.QueryLexer.prototype.emit = function (type) {\n this.lexemes.push({\n type: type,\n str: this.sliceString(),\n start: this.start,\n end: this.pos\n })\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.escapeCharacter = function () {\n this.escapeCharPositions.push(this.pos - 1)\n this.pos += 1\n}\n\nlunr.QueryLexer.prototype.next = function () {\n if (this.pos >= this.length) {\n return lunr.QueryLexer.EOS\n }\n\n var char = this.str.charAt(this.pos)\n this.pos += 1\n return char\n}\n\nlunr.QueryLexer.prototype.width = function () {\n return this.pos - this.start\n}\n\nlunr.QueryLexer.prototype.ignore = function () {\n if (this.start == this.pos) {\n this.pos += 1\n }\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.backup = function () {\n this.pos -= 1\n}\n\nlunr.QueryLexer.prototype.acceptDigitRun = function () {\n var char, charCode\n\n do {\n char = this.next()\n charCode = char.charCodeAt(0)\n } while (charCode > 47 && charCode < 58)\n\n if (char != lunr.QueryLexer.EOS) {\n this.backup()\n }\n}\n\nlunr.QueryLexer.prototype.more = function () {\n return this.pos < this.length\n}\n\nlunr.QueryLexer.EOS = 'EOS'\nlunr.QueryLexer.FIELD = 'FIELD'\nlunr.QueryLexer.TERM = 'TERM'\nlunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE'\nlunr.QueryLexer.BOOST = 'BOOST'\nlunr.QueryLexer.PRESENCE = 'PRESENCE'\n\nlunr.QueryLexer.lexField = function (lexer) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.FIELD)\n lexer.ignore()\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexTerm = function (lexer) {\n if (lexer.width() > 1) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.TERM)\n }\n\n lexer.ignore()\n\n if (lexer.more()) {\n return lunr.QueryLexer.lexText\n }\n}\n\nlunr.QueryLexer.lexEditDistance = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.EDIT_DISTANCE)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexBoost = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.BOOST)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexEOS = function (lexer) {\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n}\n\n// This matches the separator used when tokenising fields\n// within a document. These should match otherwise it is\n// not possible to search for some tokens within a document.\n//\n// It is possible for the user to change the separator on the\n// tokenizer so it _might_ clash with any other of the special\n// characters already used within the search string, e.g. :.\n//\n// This means that it is possible to change the separator in\n// such a way that makes some words unsearchable using a search\n// string.\nlunr.QueryLexer.termSeparator = lunr.tokenizer.separator\n\nlunr.QueryLexer.lexText = function (lexer) {\n while (true) {\n var char = lexer.next()\n\n if (char == lunr.QueryLexer.EOS) {\n return lunr.QueryLexer.lexEOS\n }\n\n // Escape character is '\\'\n if (char.charCodeAt(0) == 92) {\n lexer.escapeCharacter()\n continue\n }\n\n if (char == \":\") {\n return lunr.QueryLexer.lexField\n }\n\n if (char == \"~\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexEditDistance\n }\n\n if (char == \"^\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexBoost\n }\n\n // \"+\" indicates term presence is required\n // checking for length to ensure that only\n // leading \"+\" are considered\n if (char == \"+\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n // \"-\" indicates term presence is prohibited\n // checking for length to ensure that only\n // leading \"-\" are considered\n if (char == \"-\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n if (char.match(lunr.QueryLexer.termSeparator)) {\n return lunr.QueryLexer.lexTerm\n }\n }\n}\n\nlunr.QueryParser = function (str, query) {\n this.lexer = new lunr.QueryLexer (str)\n this.query = query\n this.currentClause = {}\n this.lexemeIdx = 0\n}\n\nlunr.QueryParser.prototype.parse = function () {\n this.lexer.run()\n this.lexemes = this.lexer.lexemes\n\n var state = lunr.QueryParser.parseClause\n\n while (state) {\n state = state(this)\n }\n\n return this.query\n}\n\nlunr.QueryParser.prototype.peekLexeme = function () {\n return this.lexemes[this.lexemeIdx]\n}\n\nlunr.QueryParser.prototype.consumeLexeme = function () {\n var lexeme = this.peekLexeme()\n this.lexemeIdx += 1\n return lexeme\n}\n\nlunr.QueryParser.prototype.nextClause = function () {\n var completedClause = this.currentClause\n this.query.clause(completedClause)\n this.currentClause = {}\n}\n\nlunr.QueryParser.parseClause = function (parser) {\n var lexeme = parser.peekLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.type) {\n case lunr.QueryLexer.PRESENCE:\n return lunr.QueryParser.parsePresence\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expected either a field or a term, found \" + lexeme.type\n\n if (lexeme.str.length >= 1) {\n errorMessage += \" with value '\" + lexeme.str + \"'\"\n }\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n}\n\nlunr.QueryParser.parsePresence = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.str) {\n case \"-\":\n parser.currentClause.presence = lunr.Query.presence.PROHIBITED\n break\n case \"+\":\n parser.currentClause.presence = lunr.Query.presence.REQUIRED\n break\n default:\n var errorMessage = \"unrecognised presence operator'\" + lexeme.str + \"'\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term or field, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term or field, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseField = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n if (parser.query.allFields.indexOf(lexeme.str) == -1) {\n var possibleFields = parser.query.allFields.map(function (f) { return \"'\" + f + \"'\" }).join(', '),\n errorMessage = \"unrecognised field '\" + lexeme.str + \"', possible fields: \" + possibleFields\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.fields = [lexeme.str]\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseTerm = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n parser.currentClause.term = lexeme.str.toLowerCase()\n\n if (lexeme.str.indexOf(\"*\") != -1) {\n parser.currentClause.usePipeline = false\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseEditDistance = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var editDistance = parseInt(lexeme.str, 10)\n\n if (isNaN(editDistance)) {\n var errorMessage = \"edit distance must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.editDistance = editDistance\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseBoost = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var boost = parseInt(lexeme.str, 10)\n\n if (isNaN(boost)) {\n var errorMessage = \"boost must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.boost = boost\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\n /**\n * export the module via AMD, CommonJS or as a browser global\n * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js\n */\n ;(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory)\n } else if (typeof exports === 'object') {\n /**\n * Node. Does not work with strict CommonJS, but\n * only CommonJS-like enviroments that support module.exports,\n * like Node.\n */\n module.exports = factory()\n } else {\n // Browser globals (root is window)\n root.lunr = factory()\n }\n }(this, function () {\n /**\n * Just return a value to define the module export.\n * This example returns an object, but the module\n * can return a function as the exported value.\n */\n return lunr\n }))\n})();\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport lunr from \"lunr\"\n\nimport { Search, SearchIndexConfig } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Add support for usage with `iframe-worker` polyfill\n *\n * While `importScripts` is synchronous when executed inside of a web worker,\n * it's not possible to provide a synchronous polyfilled implementation. The\n * cool thing is that awaiting a non-Promise is a noop, so extending the type\n * definition to return a `Promise` shouldn't break anything.\n *\n * @see https://bit.ly/2PjDnXi - GitHub comment\n */\ndeclare global {\n function importScripts(...urls: string[]): Promise | void\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nlet index: Search\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch (= import) multi-language support through `lunr-languages`\n *\n * This function automatically imports the stemmers necessary to process the\n * languages, which are defined through the search index configuration.\n *\n * If the worker runs inside of an `iframe` (when using `iframe-worker` as\n * a shim), the base URL for the stemmers to be loaded must be determined by\n * searching for the first `script` element with a `src` attribute, which will\n * contain the contents of this script.\n *\n * @param config - Search index configuration\n *\n * @returns Promise resolving with no result\n */\nasync function setupSearchLanguages(\n config: SearchIndexConfig\n): Promise {\n let base = \"../lunr\"\n\n /* Detect `iframe-worker` and fix base URL */\n if (typeof parent !== \"undefined\" && \"IFrameWorker\" in parent) {\n const worker = document.querySelector(\"script[src]\")!\n const [path] = worker.src.split(\"/worker\")\n\n /* Prefix base with path */\n base = base.replace(\"..\", path)\n }\n\n /* Add scripts for languages */\n const scripts = []\n for (const lang of config.lang) {\n switch (lang) {\n\n /* Add segmenter for Japanese */\n case \"ja\":\n scripts.push(`${base}/tinyseg.js`)\n break\n\n /* Add segmenter for Hindi and Thai */\n case \"hi\":\n case \"th\":\n scripts.push(`${base}/wordcut.js`)\n break\n }\n\n /* Add language support */\n if (lang !== \"en\")\n scripts.push(`${base}/min/lunr.${lang}.min.js`)\n }\n\n /* Add multi-language support */\n if (config.lang.length > 1)\n scripts.push(`${base}/min/lunr.multi.min.js`)\n\n /* Load scripts synchronously */\n if (scripts.length)\n await importScripts(\n `${base}/min/lunr.stemmer.support.min.js`,\n ...scripts\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Message handler\n *\n * @param message - Source message\n *\n * @returns Target message\n */\nexport async function handler(\n message: SearchMessage\n): Promise {\n switch (message.type) {\n\n /* Search setup message */\n case SearchMessageType.SETUP:\n await setupSearchLanguages(message.data.config)\n index = new Search(message.data)\n return {\n type: SearchMessageType.READY\n }\n\n /* Search query message */\n case SearchMessageType.QUERY:\n return {\n type: SearchMessageType.RESULT,\n data: index ? index.search(message.data) : { items: [] }\n }\n\n /* All other messages */\n default:\n throw new TypeError(\"Invalid message type\")\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Worker\n * ------------------------------------------------------------------------- */\n\n/* @ts-ignore - expose Lunr.js in global scope, or stemmers will not work */\nself.lunr = lunr\n\n/* Handle messages */\naddEventListener(\"message\", async ev => {\n postMessage(await handler(ev.data))\n})\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location and title */\n const location = doc.location\n const title = doc.title\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query clause\n */\nexport interface SearchQueryClause {\n presence: lunr.Query.presence /* Clause presence */\n term: string /* Clause term */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search query terms\n */\nexport type SearchQueryTerms = Record\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Parse a search query for analysis\n *\n * @param value - Query value\n *\n * @returns Search query clauses\n */\nexport function parseSearchQuery(\n value: string\n): SearchQueryClause[] {\n const query = new (lunr as any).Query([\"title\", \"text\"])\n const parser = new (lunr as any).QueryParser(value, query)\n\n /* Parse and return query clauses */\n parser.parse()\n return query.clauses\n}\n\n/**\n * Analyze the search query clauses in regard to the search terms found\n *\n * @param query - Search query clauses\n * @param terms - Search terms\n *\n * @returns Search query terms\n */\nexport function getSearchQueryTerms(\n query: SearchQueryClause[], terms: string[]\n): SearchQueryTerms {\n const clauses = new Set(query)\n\n /* Match query clauses against terms */\n const result: SearchQueryTerms = {}\n for (let t = 0; t < terms.length; t++)\n for (const clause of clauses)\n if (terms[t].startsWith(clause.term)) {\n result[clause.term] = true\n clauses.delete(clause)\n }\n\n /* Annotate unmatched query clauses */\n for (const clause of clauses)\n result[clause.term] = false\n\n /* Return query terms */\n return result\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n SearchDocument,\n SearchDocumentMap,\n setupSearchDocumentMap\n} from \"../document\"\nimport {\n SearchHighlightFactoryFn,\n setupSearchHighlighter\n} from \"../highlighter\"\nimport { SearchOptions } from \"../options\"\nimport {\n SearchQueryTerms,\n getSearchQueryTerms,\n parseSearchQuery\n} from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index configuration\n */\nexport interface SearchIndexConfig {\n lang: string[] /* Search languages */\n separator: string /* Search separator */\n}\n\n/**\n * Search index document\n */\nexport interface SearchIndexDocument {\n location: string /* Document location */\n title: string /* Document title */\n text: string /* Document text */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search index\n *\n * This interfaces describes the format of the `search_index.json` file which\n * is automatically built by the MkDocs search plugin.\n */\nexport interface SearchIndex {\n config: SearchIndexConfig /* Search index configuration */\n docs: SearchIndexDocument[] /* Search index documents */\n index?: object /* Prebuilt index */\n options: SearchOptions /* Search options */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search metadata\n */\nexport interface SearchMetadata {\n score: number /* Score (relevance) */\n terms: SearchQueryTerms /* Search query terms */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result document\n */\nexport type SearchResultDocument = SearchDocument & SearchMetadata\n\n/**\n * Search result item\n */\nexport type SearchResultItem = SearchResultDocument[]\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n items: SearchResultItem[] /* Search result items */\n suggestions?: string[] /* Search suggestions */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute the difference of two lists of strings\n *\n * @param a - 1st list of strings\n * @param b - 2nd list of strings\n *\n * @returns Difference\n */\nfunction difference(a: string[], b: string[]): string[] {\n const [x, y] = [new Set(a), new Set(b)]\n return [\n ...new Set([...x].filter(value => !y.has(value)))\n ]\n}\n\n/* ----------------------------------------------------------------------------\n * Class\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nexport class Search {\n\n /**\n * Search document mapping\n *\n * A mapping of URLs (including hash fragments) to the actual articles and\n * sections of the documentation. The search document mapping must be created\n * regardless of whether the index was prebuilt or not, as Lunr.js itself\n * only stores the actual index.\n */\n protected documents: SearchDocumentMap\n\n /**\n * Search highlight factory function\n */\n protected highlight: SearchHighlightFactoryFn\n\n /**\n * The underlying Lunr.js search index\n */\n protected index: lunr.Index\n\n /**\n * Search options\n */\n protected options: SearchOptions\n\n /**\n * Create the search integration\n *\n * @param data - Search index\n */\n public constructor({ config, docs, index, options }: SearchIndex) {\n this.options = options\n\n /* Set up document map and highlighter factory */\n this.documents = setupSearchDocumentMap(docs)\n this.highlight = setupSearchHighlighter(config, false)\n\n /* Set separator for tokenizer */\n lunr.tokenizer.separator = new RegExp(config.separator)\n\n /* If no index was given, create it */\n if (typeof index === \"undefined\") {\n this.index = lunr(function () {\n\n /* Set up multi-language support */\n if (config.lang.length === 1 && config.lang[0] !== \"en\") {\n this.use((lunr as any)[config.lang[0]])\n } else if (config.lang.length > 1) {\n this.use((lunr as any).multiLanguage(...config.lang))\n }\n\n /* Compute functions to be removed from the pipeline */\n const fns = difference([\n \"trimmer\", \"stopWordFilter\", \"stemmer\"\n ], options.pipeline)\n\n /* Remove functions from the pipeline for registered languages */\n for (const lang of config.lang.map(language => (\n language === \"en\" ? lunr : (lunr as any)[language]\n ))) {\n for (const fn of fns) {\n this.pipeline.remove(lang[fn])\n this.searchPipeline.remove(lang[fn])\n }\n }\n\n /* Set up reference */\n this.ref(\"location\")\n\n /* Set up fields */\n this.field(\"title\", { boost: 1e3 })\n this.field(\"text\")\n\n /* Index documents */\n for (const doc of docs)\n this.add(doc)\n })\n\n /* Handle prebuilt index */\n } else {\n this.index = lunr.Index.load(index)\n }\n }\n\n /**\n * Search for matching documents\n *\n * The search index which MkDocs provides is divided up into articles, which\n * contain the whole content of the individual pages, and sections, which only\n * contain the contents of the subsections obtained by breaking the individual\n * pages up at `h1` ... `h6`. As there may be many sections on different pages\n * with identical titles (for example within this very project, e.g. \"Usage\"\n * or \"Installation\"), they need to be put into the context of the containing\n * page. For this reason, section results are grouped within their respective\n * articles which are the top-level results that are returned.\n *\n * @param query - Query value\n *\n * @returns Search results\n */\n public search(query: string): SearchResult {\n if (query) {\n try {\n const highlight = this.highlight(query)\n\n /* Parse query to extract clauses for analysis */\n const clauses = parseSearchQuery(query)\n .filter(clause => (\n clause.presence !== lunr.Query.presence.PROHIBITED\n ))\n\n /* Perform search and post-process results */\n const groups = this.index.search(`${query}*`)\n\n /* Apply post-query boosts based on title and search query terms */\n .reduce((item, { ref, score, matchData }) => {\n const document = this.documents.get(ref)\n if (typeof document !== \"undefined\") {\n const { location, title, text, parent } = document\n\n /* Compute and analyze search query terms */\n const terms = getSearchQueryTerms(\n clauses,\n Object.keys(matchData.metadata)\n )\n\n /* Highlight title and text and apply post-query boosts */\n const boost = +!parent + +Object.values(terms).every(t => t)\n item.push({\n location,\n title: highlight(title),\n text: highlight(text),\n score: score * (1 + boost),\n terms\n })\n }\n return item\n }, [])\n\n /* Sort search results again after applying boosts */\n .sort((a, b) => b.score - a.score)\n\n /* Group search results by page */\n .reduce((items, result) => {\n const document = this.documents.get(result.location)\n if (typeof document !== \"undefined\") {\n const ref = \"parent\" in document\n ? document.parent!.location\n : document.location\n items.set(ref, [...items.get(ref) || [], result])\n }\n return items\n }, new Map())\n\n /* Generate search suggestions, if desired */\n let suggestions: string[] | undefined\n if (this.options.suggestions) {\n const titles = this.index.query(builder => {\n for (const clause of clauses)\n builder.term(clause.term, {\n fields: [\"title\"],\n presence: lunr.Query.presence.REQUIRED,\n wildcard: lunr.Query.wildcard.TRAILING\n })\n })\n\n /* Retrieve suggestions for best match */\n suggestions = titles.length\n ? Object.keys(titles[0].matchData.metadata)\n : []\n }\n\n /* Return items and suggestions */\n return {\n items: [...groups.values()],\n ...typeof suggestions !== \"undefined\" && { suggestions }\n }\n\n /* Log errors to console (for now) */\n } catch {\n console.warn(`Invalid query: ${query} \u2013 see https://bit.ly/2s3ChXG`)\n }\n }\n\n /* Return nothing in case of error or empty query */\n return { items: [] }\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * A message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * A message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * A message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * A message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n"], + "mappings": "kkCAAA;AAAA;AAAA;AAAA;AAAA,GAMC,AAAC,WAAU,CAiCZ,GAAI,GAAO,SAAU,EAAQ,CAC3B,GAAI,GAAU,GAAI,GAAK,QAEvB,SAAQ,SAAS,IACf,EAAK,QACL,EAAK,eACL,EAAK,SAGP,EAAQ,eAAe,IACrB,EAAK,SAGP,EAAO,KAAK,EAAS,GACd,EAAQ,SAGjB,EAAK,QAAU,QACf;AAAA;AAAA;AAAA,GASA,EAAK,MAAQ,GASb,EAAK,MAAM,KAAQ,SAAU,EAAQ,CAEnC,MAAO,UAAU,EAAS,CACxB,AAAI,EAAO,SAAW,QAAQ,MAC5B,QAAQ,KAAK,KAIhB,MAaH,EAAK,MAAM,SAAW,SAAU,EAAK,CACnC,MAAI,AAAkB,IAAQ,KACrB,GAEA,EAAI,YAoBf,EAAK,MAAM,MAAQ,SAAU,EAAK,CAChC,GAAI,GAAQ,KACV,MAAO,GAMT,OAHI,GAAQ,OAAO,OAAO,MACtB,EAAO,OAAO,KAAK,GAEd,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAM,EAAK,GACX,EAAM,EAAI,GAEd,GAAI,MAAM,QAAQ,GAAM,CACtB,EAAM,GAAO,EAAI,QACjB,SAGF,GAAI,MAAO,IAAQ,UACf,MAAO,IAAQ,UACf,MAAO,IAAQ,UAAW,CAC5B,EAAM,GAAO,EACb,SAGF,KAAM,IAAI,WAAU,yDAGtB,MAAO,IAET,EAAK,SAAW,SAAU,EAAQ,EAAW,EAAa,CACxD,KAAK,OAAS,EACd,KAAK,UAAY,EACjB,KAAK,aAAe,GAGtB,EAAK,SAAS,OAAS,IAEvB,EAAK,SAAS,WAAa,SAAU,EAAG,CACtC,GAAI,GAAI,EAAE,QAAQ,EAAK,SAAS,QAEhC,GAAI,IAAM,GACR,KAAM,6BAGR,GAAI,GAAW,EAAE,MAAM,EAAG,GACtB,EAAS,EAAE,MAAM,EAAI,GAEzB,MAAO,IAAI,GAAK,SAAU,EAAQ,EAAU,IAG9C,EAAK,SAAS,UAAU,SAAW,UAAY,CAC7C,MAAI,MAAK,cAAgB,MACvB,MAAK,aAAe,KAAK,UAAY,EAAK,SAAS,OAAS,KAAK,QAG5D,KAAK,cAEd;AAAA;AAAA;AAAA,GAUA,EAAK,IAAM,SAAU,EAAU,CAG7B,GAFA,KAAK,SAAW,OAAO,OAAO,MAE1B,EAAU,CACZ,KAAK,OAAS,EAAS,OAEvB,OAAS,GAAI,EAAG,EAAI,KAAK,OAAQ,IAC/B,KAAK,SAAS,EAAS,IAAM,OAG/B,MAAK,OAAS,GAWlB,EAAK,IAAI,SAAW,CAClB,UAAW,SAAU,EAAO,CAC1B,MAAO,IAGT,MAAO,UAAY,CACjB,MAAO,OAGT,SAAU,UAAY,CACpB,MAAO,KAWX,EAAK,IAAI,MAAQ,CACf,UAAW,UAAY,CACrB,MAAO,OAGT,MAAO,SAAU,EAAO,CACtB,MAAO,IAGT,SAAU,UAAY,CACpB,MAAO,KAUX,EAAK,IAAI,UAAU,SAAW,SAAU,EAAQ,CAC9C,MAAO,CAAC,CAAC,KAAK,SAAS,IAWzB,EAAK,IAAI,UAAU,UAAY,SAAU,EAAO,CAC9C,GAAI,GAAG,EAAG,EAAU,EAAe,GAEnC,GAAI,IAAU,EAAK,IAAI,SACrB,MAAO,MAGT,GAAI,IAAU,EAAK,IAAI,MACrB,MAAO,GAGT,AAAI,KAAK,OAAS,EAAM,OACtB,GAAI,KACJ,EAAI,GAEJ,GAAI,EACJ,EAAI,MAGN,EAAW,OAAO,KAAK,EAAE,UAEzB,OAAS,GAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACxC,GAAI,GAAU,EAAS,GACvB,AAAI,IAAW,GAAE,UACf,EAAa,KAAK,GAItB,MAAO,IAAI,GAAK,IAAK,IAUvB,EAAK,IAAI,UAAU,MAAQ,SAAU,EAAO,CAC1C,MAAI,KAAU,EAAK,IAAI,SACd,EAAK,IAAI,SAGd,IAAU,EAAK,IAAI,MACd,KAGF,GAAI,GAAK,IAAI,OAAO,KAAK,KAAK,UAAU,OAAO,OAAO,KAAK,EAAM,aAU1E,EAAK,IAAM,SAAU,EAAS,EAAe,CAC3C,GAAI,GAAoB,EAExB,OAAS,KAAa,GACpB,AAAI,GAAa,UACjB,IAAqB,OAAO,KAAK,EAAQ,IAAY,QAGvD,GAAI,GAAK,GAAgB,EAAoB,IAAQ,GAAoB,IAEzE,MAAO,MAAK,IAAI,EAAI,KAAK,IAAI,KAW/B,EAAK,MAAQ,SAAU,EAAK,EAAU,CACpC,KAAK,IAAM,GAAO,GAClB,KAAK,SAAW,GAAY,IAQ9B,EAAK,MAAM,UAAU,SAAW,UAAY,CAC1C,MAAO,MAAK,KAuBd,EAAK,MAAM,UAAU,OAAS,SAAU,EAAI,CAC1C,YAAK,IAAM,EAAG,KAAK,IAAK,KAAK,UACtB,MAUT,EAAK,MAAM,UAAU,MAAQ,SAAU,EAAI,CACzC,SAAK,GAAM,SAAU,EAAG,CAAE,MAAO,IAC1B,GAAI,GAAK,MAAO,EAAG,KAAK,IAAK,KAAK,UAAW,KAAK,WAE3D;AAAA;AAAA;AAAA,GAuBA,EAAK,UAAY,SAAU,EAAK,EAAU,CACxC,GAAI,GAAO,MAAQ,GAAO,KACxB,MAAO,GAGT,GAAI,MAAM,QAAQ,GAChB,MAAO,GAAI,IAAI,SAAU,EAAG,CAC1B,MAAO,IAAI,GAAK,MACd,EAAK,MAAM,SAAS,GAAG,cACvB,EAAK,MAAM,MAAM,MASvB,OAJI,GAAM,EAAI,WAAW,cACrB,EAAM,EAAI,OACV,EAAS,GAEJ,EAAW,EAAG,EAAa,EAAG,GAAY,EAAK,IAAY,CAClE,GAAI,GAAO,EAAI,OAAO,GAClB,EAAc,EAAW,EAE7B,GAAK,EAAK,MAAM,EAAK,UAAU,YAAc,GAAY,EAAM,CAE7D,GAAI,EAAc,EAAG,CACnB,GAAI,GAAgB,EAAK,MAAM,MAAM,IAAa,GAClD,EAAc,SAAc,CAAC,EAAY,GACzC,EAAc,MAAW,EAAO,OAEhC,EAAO,KACL,GAAI,GAAK,MACP,EAAI,MAAM,EAAY,GACtB,IAKN,EAAa,EAAW,GAK5B,MAAO,IAUT,EAAK,UAAU,UAAY,UAC3B;AAAA;AAAA;AAAA,GAkCA,EAAK,SAAW,UAAY,CAC1B,KAAK,OAAS,IAGhB,EAAK,SAAS,oBAAsB,OAAO,OAAO,MAmClD,EAAK,SAAS,iBAAmB,SAAU,EAAI,EAAO,CACpD,AAAI,IAAS,MAAK,qBAChB,EAAK,MAAM,KAAK,6CAA+C,GAGjE,EAAG,MAAQ,EACX,EAAK,SAAS,oBAAoB,EAAG,OAAS,GAShD,EAAK,SAAS,4BAA8B,SAAU,EAAI,CACxD,GAAI,GAAe,EAAG,OAAU,EAAG,QAAS,MAAK,oBAEjD,AAAK,GACH,EAAK,MAAM,KAAK;AAAA,EAAmG,IAcvH,EAAK,SAAS,KAAO,SAAU,EAAY,CACzC,GAAI,GAAW,GAAI,GAAK,SAExB,SAAW,QAAQ,SAAU,EAAQ,CACnC,GAAI,GAAK,EAAK,SAAS,oBAAoB,GAE3C,GAAI,EACF,EAAS,IAAI,OAEb,MAAM,IAAI,OAAM,sCAAwC,KAIrD,GAUT,EAAK,SAAS,UAAU,IAAM,UAAY,CACxC,GAAI,GAAM,MAAM,UAAU,MAAM,KAAK,WAErC,EAAI,QAAQ,SAAU,EAAI,CACxB,EAAK,SAAS,4BAA4B,GAC1C,KAAK,OAAO,KAAK,IAChB,OAYL,EAAK,SAAS,UAAU,MAAQ,SAAU,EAAY,EAAO,CAC3D,EAAK,SAAS,4BAA4B,GAE1C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,GAAI,GAAO,GACT,KAAM,IAAI,OAAM,0BAGlB,EAAM,EAAM,EACZ,KAAK,OAAO,OAAO,EAAK,EAAG,IAY7B,EAAK,SAAS,UAAU,OAAS,SAAU,EAAY,EAAO,CAC5D,EAAK,SAAS,4BAA4B,GAE1C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,GAAI,GAAO,GACT,KAAM,IAAI,OAAM,0BAGlB,KAAK,OAAO,OAAO,EAAK,EAAG,IAQ7B,EAAK,SAAS,UAAU,OAAS,SAAU,EAAI,CAC7C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,AAAI,GAAO,IAIX,KAAK,OAAO,OAAO,EAAK,IAU1B,EAAK,SAAS,UAAU,IAAM,SAAU,EAAQ,CAG9C,OAFI,GAAc,KAAK,OAAO,OAErB,EAAI,EAAG,EAAI,EAAa,IAAK,CAIpC,OAHI,GAAK,KAAK,OAAO,GACjB,EAAO,GAEF,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAS,EAAG,EAAO,GAAI,EAAG,GAE9B,GAAI,KAAW,MAA6B,IAAW,IAEvD,GAAI,MAAM,QAAQ,GAChB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAK,KAAK,EAAO,QAGnB,GAAK,KAAK,GAId,EAAS,EAGX,MAAO,IAaT,EAAK,SAAS,UAAU,UAAY,SAAU,EAAK,EAAU,CAC3D,GAAI,GAAQ,GAAI,GAAK,MAAO,EAAK,GAEjC,MAAO,MAAK,IAAI,CAAC,IAAQ,IAAI,SAAU,EAAG,CACxC,MAAO,GAAE,cAQb,EAAK,SAAS,UAAU,MAAQ,UAAY,CAC1C,KAAK,OAAS,IAUhB,EAAK,SAAS,UAAU,OAAS,UAAY,CAC3C,MAAO,MAAK,OAAO,IAAI,SAAU,EAAI,CACnC,SAAK,SAAS,4BAA4B,GAEnC,EAAG,SAGd;AAAA;AAAA;AAAA,GAqBA,EAAK,OAAS,SAAU,EAAU,CAChC,KAAK,WAAa,EAClB,KAAK,SAAW,GAAY,IAc9B,EAAK,OAAO,UAAU,iBAAmB,SAAU,EAAO,CAExD,GAAI,KAAK,SAAS,QAAU,EAC1B,MAAO,GAST,OANI,GAAQ,EACR,EAAM,KAAK,SAAS,OAAS,EAC7B,EAAc,EAAM,EACpB,EAAa,KAAK,MAAM,EAAc,GACtC,EAAa,KAAK,SAAS,EAAa,GAErC,EAAc,GACf,GAAa,GACf,GAAQ,GAGN,EAAa,GACf,GAAM,GAGJ,GAAc,IAIlB,EAAc,EAAM,EACpB,EAAa,EAAQ,KAAK,MAAM,EAAc,GAC9C,EAAa,KAAK,SAAS,EAAa,GAO1C,GAJI,GAAc,GAId,EAAa,EACf,MAAO,GAAa,EAGtB,GAAI,EAAa,EACf,MAAQ,GAAa,GAAK,GAa9B,EAAK,OAAO,UAAU,OAAS,SAAU,EAAW,EAAK,CACvD,KAAK,OAAO,EAAW,EAAK,UAAY,CACtC,KAAM,qBAYV,EAAK,OAAO,UAAU,OAAS,SAAU,EAAW,EAAK,EAAI,CAC3D,KAAK,WAAa,EAClB,GAAI,GAAW,KAAK,iBAAiB,GAErC,AAAI,KAAK,SAAS,IAAa,EAC7B,KAAK,SAAS,EAAW,GAAK,EAAG,KAAK,SAAS,EAAW,GAAI,GAE9D,KAAK,SAAS,OAAO,EAAU,EAAG,EAAW,IASjD,EAAK,OAAO,UAAU,UAAY,UAAY,CAC5C,GAAI,KAAK,WAAY,MAAO,MAAK,WAKjC,OAHI,GAAe,EACf,EAAiB,KAAK,SAAS,OAE1B,EAAI,EAAG,EAAI,EAAgB,GAAK,EAAG,CAC1C,GAAI,GAAM,KAAK,SAAS,GACxB,GAAgB,EAAM,EAGxB,MAAO,MAAK,WAAa,KAAK,KAAK,IASrC,EAAK,OAAO,UAAU,IAAM,SAAU,EAAa,CAOjD,OANI,GAAa,EACb,EAAI,KAAK,SAAU,EAAI,EAAY,SACnC,EAAO,EAAE,OAAQ,EAAO,EAAE,OAC1B,EAAO,EAAG,EAAO,EACjB,EAAI,EAAG,EAAI,EAER,EAAI,GAAQ,EAAI,GACrB,EAAO,EAAE,GAAI,EAAO,EAAE,GACtB,AAAI,EAAO,EACT,GAAK,EACA,AAAI,EAAO,EAChB,GAAK,EACI,GAAQ,GACjB,IAAc,EAAE,EAAI,GAAK,EAAE,EAAI,GAC/B,GAAK,EACL,GAAK,GAIT,MAAO,IAUT,EAAK,OAAO,UAAU,WAAa,SAAU,EAAa,CACxD,MAAO,MAAK,IAAI,GAAe,KAAK,aAAe,GAQrD,EAAK,OAAO,UAAU,QAAU,UAAY,CAG1C,OAFI,GAAS,GAAI,OAAO,KAAK,SAAS,OAAS,GAEtC,EAAI,EAAG,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,GAAK,EAAG,IACvD,EAAO,GAAK,KAAK,SAAS,GAG5B,MAAO,IAQT,EAAK,OAAO,UAAU,OAAS,UAAY,CACzC,MAAO,MAAK,UAGd;AAAA;AAAA;AAAA;AAAA,GAiBA,EAAK,QAAW,UAAU,CACxB,GAAI,GAAY,CACZ,QAAY,MACZ,OAAW,OACX,KAAS,OACT,KAAS,OACT,KAAS,MACT,IAAQ,MACR,KAAS,KACT,MAAU,MACV,IAAQ,IACR,MAAU,MACV,QAAY,MACZ,MAAU,MACV,KAAS,MACT,MAAU,KACV,QAAY,MACZ,QAAY,MACZ,QAAY,MACZ,MAAU,KACV,MAAU,MACV,OAAW,MACX,KAAS,OAGX,EAAY,CACV,MAAU,KACV,MAAU,GACV,MAAU,KACV,MAAU,KACV,KAAS,KACT,IAAQ,GACR,KAAS,IAGX,EAAI,WACJ,EAAI,WACJ,EAAI,EAAI,aACR,EAAI,EAAI,WAER,EAAO,KAAO,EAAI,KAAO,EAAI,EAC7B,EAAO,KAAO,EAAI,KAAO,EAAI,EAAI,IAAM,EAAI,MAC3C,EAAO,KAAO,EAAI,KAAO,EAAI,EAAI,EAAI,EACrC,EAAM,KAAO,EAAI,KAAO,EAEtB,EAAU,GAAI,QAAO,GACrB,EAAU,GAAI,QAAO,GACrB,EAAU,GAAI,QAAO,GACrB,EAAS,GAAI,QAAO,GAEpB,EAAQ,kBACR,EAAS,iBACT,EAAQ,aACR,EAAS,kBACT,EAAU,KACV,EAAW,cACX,EAAW,GAAI,QAAO,sBACtB,EAAW,GAAI,QAAO,IAAM,EAAI,EAAI,gBAEpC,EAAQ,mBACR,EAAO,2IAEP,EAAO,iDAEP,EAAO,sFACP,EAAQ,oBAER,EAAO,WACP,EAAS,MACT,EAAQ,GAAI,QAAO,IAAM,EAAI,EAAI,gBAEjC,EAAgB,SAAuB,EAAG,CAC5C,GAAI,GACF,EACA,EACA,EACA,EACA,EACA,EAEF,GAAI,EAAE,OAAS,EAAK,MAAO,GAiB3B,GAfA,EAAU,EAAE,OAAO,EAAE,GACjB,GAAW,KACb,GAAI,EAAQ,cAAgB,EAAE,OAAO,IAIvC,EAAK,EACL,EAAM,EAEN,AAAI,EAAG,KAAK,GAAM,EAAI,EAAE,QAAQ,EAAG,QAC1B,EAAI,KAAK,IAAM,GAAI,EAAE,QAAQ,EAAI,SAG1C,EAAK,EACL,EAAM,EACF,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAK,EACD,EAAG,KAAK,EAAG,KACb,GAAK,EACL,EAAI,EAAE,QAAQ,EAAG,aAEV,EAAI,KAAK,GAAI,CACtB,GAAI,GAAK,EAAI,KAAK,GAClB,EAAO,EAAG,GACV,EAAM,EACF,EAAI,KAAK,IACX,GAAI,EACJ,EAAM,EACN,EAAM,EACN,EAAM,EACN,AAAI,EAAI,KAAK,GAAM,EAAI,EAAI,IACtB,AAAI,EAAI,KAAK,GAAM,GAAK,EAAS,EAAI,EAAE,QAAQ,EAAG,KAC9C,EAAI,KAAK,IAAM,GAAI,EAAI,MAMpC,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAI,EAAO,IAKb,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAS,EAAG,GACZ,EAAK,EACD,EAAG,KAAK,IACV,GAAI,EAAO,EAAU,IAMzB,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAS,EAAG,GACZ,EAAK,EACD,EAAG,KAAK,IACV,GAAI,EAAO,EAAU,IAOzB,GAFA,EAAK,EACL,EAAM,EACF,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAK,EACD,EAAG,KAAK,IACV,GAAI,WAEG,EAAI,KAAK,GAAI,CACtB,GAAI,GAAK,EAAI,KAAK,GAClB,EAAO,EAAG,GAAK,EAAG,GAClB,EAAM,EACF,EAAI,KAAK,IACX,GAAI,GAMR,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAK,EACL,EAAM,EACN,EAAM,EACF,GAAG,KAAK,IAAU,EAAI,KAAK,IAAS,CAAE,EAAI,KAAK,KACjD,GAAI,GAIR,SAAK,EACL,EAAM,EACF,EAAG,KAAK,IAAM,EAAI,KAAK,IACzB,GAAK,EACL,EAAI,EAAE,QAAQ,EAAG,KAKf,GAAW,KACb,GAAI,EAAQ,cAAgB,EAAE,OAAO,IAGhC,GAGT,MAAO,UAAU,EAAO,CACtB,MAAO,GAAM,OAAO,OAIxB,EAAK,SAAS,iBAAiB,EAAK,QAAS,WAC7C;AAAA;AAAA;AAAA,GAkBA,EAAK,uBAAyB,SAAU,EAAW,CACjD,GAAI,GAAQ,EAAU,OAAO,SAAU,EAAM,EAAU,CACrD,SAAK,GAAY,EACV,GACN,IAEH,MAAO,UAAU,EAAO,CACtB,GAAI,GAAS,EAAM,EAAM,cAAgB,EAAM,WAAY,MAAO,KAiBtE,EAAK,eAAiB,EAAK,uBAAuB,CAChD,IACA,OACA,QACA,SACA,QACA,MACA,SACA,OACA,KACA,QACA,KACA,MACA,MACA,MACA,KACA,KACA,KACA,UACA,OACA,MACA,KACA,MACA,SACA,QACA,OACA,MACA,KACA,OACA,SACA,OACA,OACA,QACA,MACA,OACA,MACA,MACA,MACA,MACA,OACA,KACA,MACA,OACA,MACA,MACA,MACA,UACA,IACA,KACA,KACA,OACA,KACA,KACA,MACA,OACA,QACA,MACA,OACA,SACA,MACA,KACA,QACA,OACA,OACA,KACA,UACA,KACA,MACA,MACA,KACA,MACA,QACA,KACA,OACA,KACA,QACA,MACA,MACA,SACA,OACA,MACA,OACA,MACA,SACA,QACA,KACA,OACA,OACA,OACA,MACA,QACA,OACA,OACA,QACA,QACA,OACA,OACA,MACA,KACA,MACA,OACA,KACA,QACA,MACA,KACA,OACA,OACA,OACA,QACA,QACA,QACA,MACA,OACA,MACA,OACA,OACA,QACA,MACA,MACA,SAGF,EAAK,SAAS,iBAAiB,EAAK,eAAgB,kBACpD;AAAA;AAAA;AAAA,GAoBA,EAAK,QAAU,SAAU,EAAO,CAC9B,MAAO,GAAM,OAAO,SAAU,EAAG,CAC/B,MAAO,GAAE,QAAQ,OAAQ,IAAI,QAAQ,OAAQ,OAIjD,EAAK,SAAS,iBAAiB,EAAK,QAAS,WAC7C;AAAA;AAAA;AAAA,GA0BA,EAAK,SAAW,UAAY,CAC1B,KAAK,MAAQ,GACb,KAAK,MAAQ,GACb,KAAK,GAAK,EAAK,SAAS,QACxB,EAAK,SAAS,SAAW,GAW3B,EAAK,SAAS,QAAU,EASxB,EAAK,SAAS,UAAY,SAAU,EAAK,CAGvC,OAFI,GAAU,GAAI,GAAK,SAAS,QAEvB,EAAI,EAAG,EAAM,EAAI,OAAQ,EAAI,EAAK,IACzC,EAAQ,OAAO,EAAI,IAGrB,SAAQ,SACD,EAAQ,MAYjB,EAAK,SAAS,WAAa,SAAU,EAAQ,CAC3C,MAAI,gBAAkB,GACb,EAAK,SAAS,gBAAgB,EAAO,KAAM,EAAO,cAElD,EAAK,SAAS,WAAW,EAAO,OAmB3C,EAAK,SAAS,gBAAkB,SAAU,EAAK,EAAc,CAS3D,OARI,GAAO,GAAI,GAAK,SAEhB,EAAQ,CAAC,CACX,KAAM,EACN,eAAgB,EAChB,IAAK,IAGA,EAAM,QAAQ,CACnB,GAAI,GAAQ,EAAM,MAGlB,GAAI,EAAM,IAAI,OAAS,EAAG,CACxB,GAAI,GAAO,EAAM,IAAI,OAAO,GACxB,EAEJ,AAAI,IAAQ,GAAM,KAAK,MACrB,EAAa,EAAM,KAAK,MAAM,GAE9B,GAAa,GAAI,GAAK,SACtB,EAAM,KAAK,MAAM,GAAQ,GAGvB,EAAM,IAAI,QAAU,GACtB,GAAW,MAAQ,IAGrB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eACtB,IAAK,EAAM,IAAI,MAAM,KAIzB,GAAI,EAAM,gBAAkB,EAK5B,IAAI,KAAO,GAAM,KAAK,MACpB,GAAI,GAAgB,EAAM,KAAK,MAAM,SAChC,CACL,GAAI,GAAgB,GAAI,GAAK,SAC7B,EAAM,KAAK,MAAM,KAAO,EAiC1B,GA9BI,EAAM,IAAI,QAAU,GACtB,GAAc,MAAQ,IAGxB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,MAMT,EAAM,IAAI,OAAS,GACrB,EAAM,KAAK,CACT,KAAM,EAAM,KACZ,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,IAAI,MAAM,KAMrB,EAAM,IAAI,QAAU,GACtB,GAAM,KAAK,MAAQ,IAMjB,EAAM,IAAI,QAAU,EAAG,CACzB,GAAI,KAAO,GAAM,KAAK,MACpB,GAAI,GAAmB,EAAM,KAAK,MAAM,SACnC,CACL,GAAI,GAAmB,GAAI,GAAK,SAChC,EAAM,KAAK,MAAM,KAAO,EAG1B,AAAI,EAAM,IAAI,QAAU,GACtB,GAAiB,MAAQ,IAG3B,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,IAAI,MAAM,KAOzB,GAAI,EAAM,IAAI,OAAS,EAAG,CACxB,GAAI,GAAQ,EAAM,IAAI,OAAO,GACzB,EAAQ,EAAM,IAAI,OAAO,GACzB,EAEJ,AAAI,IAAS,GAAM,KAAK,MACtB,EAAgB,EAAM,KAAK,MAAM,GAEjC,GAAgB,GAAI,GAAK,SACzB,EAAM,KAAK,MAAM,GAAS,GAGxB,EAAM,IAAI,QAAU,GACtB,GAAc,MAAQ,IAGxB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAQ,EAAM,IAAI,MAAM,OAKnC,MAAO,IAaT,EAAK,SAAS,WAAa,SAAU,EAAK,CAYxC,OAXI,GAAO,GAAI,GAAK,SAChB,EAAO,EAUF,EAAI,EAAG,EAAM,EAAI,OAAQ,EAAI,EAAK,IAAK,CAC9C,GAAI,GAAO,EAAI,GACX,EAAS,GAAK,EAAM,EAExB,GAAI,GAAQ,IACV,EAAK,MAAM,GAAQ,EACnB,EAAK,MAAQ,MAER,CACL,GAAI,GAAO,GAAI,GAAK,SACpB,EAAK,MAAQ,EAEb,EAAK,MAAM,GAAQ,EACnB,EAAO,GAIX,MAAO,IAaT,EAAK,SAAS,UAAU,QAAU,UAAY,CAQ5C,OAPI,GAAQ,GAER,EAAQ,CAAC,CACX,OAAQ,GACR,KAAM,OAGD,EAAM,QAAQ,CACnB,GAAI,GAAQ,EAAM,MACd,EAAQ,OAAO,KAAK,EAAM,KAAK,OAC/B,EAAM,EAAM,OAEhB,AAAI,EAAM,KAAK,OAKb,GAAM,OAAO,OAAO,GACpB,EAAM,KAAK,EAAM,SAGnB,OAAS,GAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,GAAI,GAAO,EAAM,GAEjB,EAAM,KAAK,CACT,OAAQ,EAAM,OAAO,OAAO,GAC5B,KAAM,EAAM,KAAK,MAAM,MAK7B,MAAO,IAaT,EAAK,SAAS,UAAU,SAAW,UAAY,CAS7C,GAAI,KAAK,KACP,MAAO,MAAK,KAOd,OAJI,GAAM,KAAK,MAAQ,IAAM,IACzB,EAAS,OAAO,KAAK,KAAK,OAAO,OACjC,EAAM,EAAO,OAER,EAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,GAAI,GAAQ,EAAO,GACf,EAAO,KAAK,MAAM,GAEtB,EAAM,EAAM,EAAQ,EAAK,GAG3B,MAAO,IAaT,EAAK,SAAS,UAAU,UAAY,SAAU,EAAG,CAU/C,OATI,GAAS,GAAI,GAAK,SAClB,EAAQ,OAER,EAAQ,CAAC,CACX,MAAO,EACP,OAAQ,EACR,KAAM,OAGD,EAAM,QAAQ,CACnB,EAAQ,EAAM,MAWd,OALI,GAAS,OAAO,KAAK,EAAM,MAAM,OACjC,EAAO,EAAO,OACd,EAAS,OAAO,KAAK,EAAM,KAAK,OAChC,EAAO,EAAO,OAET,EAAI,EAAG,EAAI,EAAM,IAGxB,OAFI,GAAQ,EAAO,GAEV,EAAI,EAAG,EAAI,EAAM,IAAK,CAC7B,GAAI,GAAQ,EAAO,GAEnB,GAAI,GAAS,GAAS,GAAS,IAAK,CAClC,GAAI,GAAO,EAAM,KAAK,MAAM,GACxB,EAAQ,EAAM,MAAM,MAAM,GAC1B,EAAQ,EAAK,OAAS,EAAM,MAC5B,EAAO,OAEX,AAAI,IAAS,GAAM,OAAO,MAIxB,GAAO,EAAM,OAAO,MAAM,GAC1B,EAAK,MAAQ,EAAK,OAAS,GAM3B,GAAO,GAAI,GAAK,SAChB,EAAK,MAAQ,EACb,EAAM,OAAO,MAAM,GAAS,GAG9B,EAAM,KAAK,CACT,MAAO,EACP,OAAQ,EACR,KAAM,MAOhB,MAAO,IAET,EAAK,SAAS,QAAU,UAAY,CAClC,KAAK,aAAe,GACpB,KAAK,KAAO,GAAI,GAAK,SACrB,KAAK,eAAiB,GACtB,KAAK,eAAiB,IAGxB,EAAK,SAAS,QAAQ,UAAU,OAAS,SAAU,EAAM,CACvD,GAAI,GACA,EAAe,EAEnB,GAAI,EAAO,KAAK,aACd,KAAM,IAAI,OAAO,+BAGnB,OAAS,GAAI,EAAG,EAAI,EAAK,QAAU,EAAI,KAAK,aAAa,QACnD,EAAK,IAAM,KAAK,aAAa,GAD8B,IAE/D,IAGF,KAAK,SAAS,GAEd,AAAI,KAAK,eAAe,QAAU,EAChC,EAAO,KAAK,KAEZ,EAAO,KAAK,eAAe,KAAK,eAAe,OAAS,GAAG,MAG7D,OAAS,GAAI,EAAc,EAAI,EAAK,OAAQ,IAAK,CAC/C,GAAI,GAAW,GAAI,GAAK,SACpB,EAAO,EAAK,GAEhB,EAAK,MAAM,GAAQ,EAEnB,KAAK,eAAe,KAAK,CACvB,OAAQ,EACR,KAAM,EACN,MAAO,IAGT,EAAO,EAGT,EAAK,MAAQ,GACb,KAAK,aAAe,GAGtB,EAAK,SAAS,QAAQ,UAAU,OAAS,UAAY,CACnD,KAAK,SAAS,IAGhB,EAAK,SAAS,QAAQ,UAAU,SAAW,SAAU,EAAQ,CAC3D,OAAS,GAAI,KAAK,eAAe,OAAS,EAAG,GAAK,EAAQ,IAAK,CAC7D,GAAI,GAAO,KAAK,eAAe,GAC3B,EAAW,EAAK,MAAM,WAE1B,AAAI,IAAY,MAAK,eACnB,EAAK,OAAO,MAAM,EAAK,MAAQ,KAAK,eAAe,GAInD,GAAK,MAAM,KAAO,EAElB,KAAK,eAAe,GAAY,EAAK,OAGvC,KAAK,eAAe,QAGxB;AAAA;AAAA;AAAA,GAqBA,EAAK,MAAQ,SAAU,EAAO,CAC5B,KAAK,cAAgB,EAAM,cAC3B,KAAK,aAAe,EAAM,aAC1B,KAAK,SAAW,EAAM,SACtB,KAAK,OAAS,EAAM,OACpB,KAAK,SAAW,EAAM,UA0ExB,EAAK,MAAM,UAAU,OAAS,SAAU,EAAa,CACnD,MAAO,MAAK,MAAM,SAAU,EAAO,CACjC,GAAI,GAAS,GAAI,GAAK,YAAY,EAAa,GAC/C,EAAO,WA6BX,EAAK,MAAM,UAAU,MAAQ,SAAU,EAAI,CAoBzC,OAZI,GAAQ,GAAI,GAAK,MAAM,KAAK,QAC5B,EAAiB,OAAO,OAAO,MAC/B,EAAe,OAAO,OAAO,MAC7B,EAAiB,OAAO,OAAO,MAC/B,EAAkB,OAAO,OAAO,MAChC,EAAoB,OAAO,OAAO,MAO7B,EAAI,EAAG,EAAI,KAAK,OAAO,OAAQ,IACtC,EAAa,KAAK,OAAO,IAAM,GAAI,GAAK,OAG1C,EAAG,KAAK,EAAO,GAEf,OAAS,GAAI,EAAG,EAAI,EAAM,QAAQ,OAAQ,IAAK,CAS7C,GAAI,GAAS,EAAM,QAAQ,GACvB,EAAQ,KACR,EAAgB,EAAK,IAAI,MAE7B,AAAI,EAAO,YACT,EAAQ,KAAK,SAAS,UAAU,EAAO,KAAM,CAC3C,OAAQ,EAAO,SAGjB,EAAQ,CAAC,EAAO,MAGlB,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GAQjB,EAAO,KAAO,EAOd,GAAI,GAAe,EAAK,SAAS,WAAW,GACxC,EAAgB,KAAK,SAAS,UAAU,GAAc,UAQ1D,GAAI,EAAc,SAAW,GAAK,EAAO,WAAa,EAAK,MAAM,SAAS,SAAU,CAClF,OAAS,GAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAC7C,GAAI,GAAQ,EAAO,OAAO,GAC1B,EAAgB,GAAS,EAAK,IAAI,MAGpC,MAGF,OAAS,GAAI,EAAG,EAAI,EAAc,OAAQ,IASxC,OAJI,GAAe,EAAc,GAC7B,EAAU,KAAK,cAAc,GAC7B,EAAY,EAAQ,OAEf,EAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAS7C,GAAI,GAAQ,EAAO,OAAO,GACtB,EAAe,EAAQ,GACvB,EAAuB,OAAO,KAAK,GACnC,EAAY,EAAe,IAAM,EACjC,EAAuB,GAAI,GAAK,IAAI,GAoBxC,GAbI,EAAO,UAAY,EAAK,MAAM,SAAS,UACzC,GAAgB,EAAc,MAAM,GAEhC,EAAgB,KAAW,QAC7B,GAAgB,GAAS,EAAK,IAAI,WASlC,EAAO,UAAY,EAAK,MAAM,SAAS,WAAY,CACrD,AAAI,EAAkB,KAAW,QAC/B,GAAkB,GAAS,EAAK,IAAI,OAGtC,EAAkB,GAAS,EAAkB,GAAO,MAAM,GAO1D,SAgBF,GANA,EAAa,GAAO,OAAO,EAAW,EAAO,MAAO,SAAU,GAAG,GAAG,CAAE,MAAO,IAAI,KAM7E,GAAe,GAInB,QAAS,GAAI,EAAG,EAAI,EAAqB,OAAQ,IAAK,CAOpD,GAAI,GAAsB,EAAqB,GAC3C,EAAmB,GAAI,GAAK,SAAU,EAAqB,GAC3D,EAAW,EAAa,GACxB,EAEJ,AAAK,GAAa,EAAe,MAAuB,OACtD,EAAe,GAAoB,GAAI,GAAK,UAAW,EAAc,EAAO,GAE5E,EAAW,IAAI,EAAc,EAAO,GAKxC,EAAe,GAAa,KAWlC,GAAI,EAAO,WAAa,EAAK,MAAM,SAAS,SAC1C,OAAS,GAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAC7C,GAAI,GAAQ,EAAO,OAAO,GAC1B,EAAgB,GAAS,EAAgB,GAAO,UAAU,IAahE,OAHI,GAAqB,EAAK,IAAI,SAC9B,EAAuB,EAAK,IAAI,MAE3B,EAAI,EAAG,EAAI,KAAK,OAAO,OAAQ,IAAK,CAC3C,GAAI,GAAQ,KAAK,OAAO,GAExB,AAAI,EAAgB,IAClB,GAAqB,EAAmB,UAAU,EAAgB,KAGhE,EAAkB,IACpB,GAAuB,EAAqB,MAAM,EAAkB,KAIxE,GAAI,GAAoB,OAAO,KAAK,GAChC,EAAU,GACV,EAAU,OAAO,OAAO,MAY5B,GAAI,EAAM,YAAa,CACrB,EAAoB,OAAO,KAAK,KAAK,cAErC,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CACjD,GAAI,GAAmB,EAAkB,GACrC,EAAW,EAAK,SAAS,WAAW,GACxC,EAAe,GAAoB,GAAI,GAAK,WAIhD,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CASjD,GAAI,GAAW,EAAK,SAAS,WAAW,EAAkB,IACtD,EAAS,EAAS,OAEtB,GAAI,EAAC,EAAmB,SAAS,IAI7B,GAAqB,SAAS,GAIlC,IAAI,GAAc,KAAK,aAAa,GAChC,EAAQ,EAAa,EAAS,WAAW,WAAW,GACpD,EAEJ,GAAK,GAAW,EAAQ,MAAa,OACnC,EAAS,OAAS,EAClB,EAAS,UAAU,QAAQ,EAAe,QACrC,CACL,GAAI,GAAQ,CACV,IAAK,EACL,MAAO,EACP,UAAW,EAAe,IAE5B,EAAQ,GAAU,EAClB,EAAQ,KAAK,KAOjB,MAAO,GAAQ,KAAK,SAAU,GAAG,GAAG,CAClC,MAAO,IAAE,MAAQ,GAAE,SAYvB,EAAK,MAAM,UAAU,OAAS,UAAY,CACxC,GAAI,GAAgB,OAAO,KAAK,KAAK,eAClC,OACA,IAAI,SAAU,EAAM,CACnB,MAAO,CAAC,EAAM,KAAK,cAAc,KAChC,MAED,EAAe,OAAO,KAAK,KAAK,cACjC,IAAI,SAAU,EAAK,CAClB,MAAO,CAAC,EAAK,KAAK,aAAa,GAAK,WACnC,MAEL,MAAO,CACL,QAAS,EAAK,QACd,OAAQ,KAAK,OACb,aAAc,EACd,cAAe,EACf,SAAU,KAAK,SAAS,WAU5B,EAAK,MAAM,KAAO,SAAU,EAAiB,CAC3C,GAAI,GAAQ,GACR,EAAe,GACf,EAAoB,EAAgB,aACpC,EAAgB,OAAO,OAAO,MAC9B,EAA0B,EAAgB,cAC1C,EAAkB,GAAI,GAAK,SAAS,QACpC,EAAW,EAAK,SAAS,KAAK,EAAgB,UAElD,AAAI,EAAgB,SAAW,EAAK,SAClC,EAAK,MAAM,KAAK,4EAA8E,EAAK,QAAU,sCAAwC,EAAgB,QAAU,KAGjL,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CACjD,GAAI,GAAQ,EAAkB,GAC1B,EAAM,EAAM,GACZ,EAAW,EAAM,GAErB,EAAa,GAAO,GAAI,GAAK,OAAO,GAGtC,OAAS,GAAI,EAAG,EAAI,EAAwB,OAAQ,IAAK,CACvD,GAAI,GAAQ,EAAwB,GAChC,EAAO,EAAM,GACb,EAAU,EAAM,GAEpB,EAAgB,OAAO,GACvB,EAAc,GAAQ,EAGxB,SAAgB,SAEhB,EAAM,OAAS,EAAgB,OAE/B,EAAM,aAAe,EACrB,EAAM,cAAgB,EACtB,EAAM,SAAW,EAAgB,KACjC,EAAM,SAAW,EAEV,GAAI,GAAK,MAAM,IAExB;AAAA;AAAA;AAAA,GA6BA,EAAK,QAAU,UAAY,CACzB,KAAK,KAAO,KACZ,KAAK,QAAU,OAAO,OAAO,MAC7B,KAAK,WAAa,OAAO,OAAO,MAChC,KAAK,cAAgB,OAAO,OAAO,MACnC,KAAK,qBAAuB,GAC5B,KAAK,aAAe,GACpB,KAAK,UAAY,EAAK,UACtB,KAAK,SAAW,GAAI,GAAK,SACzB,KAAK,eAAiB,GAAI,GAAK,SAC/B,KAAK,cAAgB,EACrB,KAAK,GAAK,IACV,KAAK,IAAM,IACX,KAAK,UAAY,EACjB,KAAK,kBAAoB,IAe3B,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAK,CAC1C,KAAK,KAAO,GAmCd,EAAK,QAAQ,UAAU,MAAQ,SAAU,EAAW,EAAY,CAC9D,GAAI,KAAK,KAAK,GACZ,KAAM,IAAI,YAAY,UAAY,EAAY,oCAGhD,KAAK,QAAQ,GAAa,GAAc,IAW1C,EAAK,QAAQ,UAAU,EAAI,SAAU,EAAQ,CAC3C,AAAI,EAAS,EACX,KAAK,GAAK,EACL,AAAI,EAAS,EAClB,KAAK,GAAK,EAEV,KAAK,GAAK,GAWd,EAAK,QAAQ,UAAU,GAAK,SAAU,EAAQ,CAC5C,KAAK,IAAM,GAoBb,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAK,EAAY,CACtD,GAAI,GAAS,EAAI,KAAK,MAClB,EAAS,OAAO,KAAK,KAAK,SAE9B,KAAK,WAAW,GAAU,GAAc,GACxC,KAAK,eAAiB,EAEtB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAY,EAAO,GACnB,EAAY,KAAK,QAAQ,GAAW,UACpC,EAAQ,EAAY,EAAU,GAAO,EAAI,GACzC,EAAS,KAAK,UAAU,EAAO,CAC7B,OAAQ,CAAC,KAEX,EAAQ,KAAK,SAAS,IAAI,GAC1B,EAAW,GAAI,GAAK,SAAU,EAAQ,GACtC,EAAa,OAAO,OAAO,MAE/B,KAAK,qBAAqB,GAAY,EACtC,KAAK,aAAa,GAAY,EAG9B,KAAK,aAAa,IAAa,EAAM,OAGrC,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GAUjB,GARI,EAAW,IAAS,MACtB,GAAW,GAAQ,GAGrB,EAAW,IAAS,EAIhB,KAAK,cAAc,IAAS,KAAW,CACzC,GAAI,GAAU,OAAO,OAAO,MAC5B,EAAQ,OAAY,KAAK,UACzB,KAAK,WAAa,EAElB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAQ,EAAO,IAAM,OAAO,OAAO,MAGrC,KAAK,cAAc,GAAQ,EAI7B,AAAI,KAAK,cAAc,GAAM,GAAW,IAAW,MACjD,MAAK,cAAc,GAAM,GAAW,GAAU,OAAO,OAAO,OAK9D,OAAS,GAAI,EAAG,EAAI,KAAK,kBAAkB,OAAQ,IAAK,CACtD,GAAI,GAAc,KAAK,kBAAkB,GACrC,EAAW,EAAK,SAAS,GAE7B,AAAI,KAAK,cAAc,GAAM,GAAW,GAAQ,IAAgB,MAC9D,MAAK,cAAc,GAAM,GAAW,GAAQ,GAAe,IAG7D,KAAK,cAAc,GAAM,GAAW,GAAQ,GAAa,KAAK,OAYtE,EAAK,QAAQ,UAAU,6BAA+B,UAAY,CAOhE,OALI,GAAY,OAAO,KAAK,KAAK,cAC7B,EAAiB,EAAU,OAC3B,EAAc,GACd,EAAqB,GAEhB,EAAI,EAAG,EAAI,EAAgB,IAAK,CACvC,GAAI,GAAW,EAAK,SAAS,WAAW,EAAU,IAC9C,EAAQ,EAAS,UAErB,EAAmB,IAAW,GAAmB,GAAS,GAC1D,EAAmB,IAAU,EAE7B,EAAY,IAAW,GAAY,GAAS,GAC5C,EAAY,IAAU,KAAK,aAAa,GAK1C,OAFI,GAAS,OAAO,KAAK,KAAK,SAErB,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAY,EAAO,GACvB,EAAY,GAAa,EAAY,GAAa,EAAmB,GAGvE,KAAK,mBAAqB,GAQ5B,EAAK,QAAQ,UAAU,mBAAqB,UAAY,CAMtD,OALI,GAAe,GACf,EAAY,OAAO,KAAK,KAAK,sBAC7B,EAAkB,EAAU,OAC5B,EAAe,OAAO,OAAO,MAExB,EAAI,EAAG,EAAI,EAAiB,IAAK,CAaxC,OAZI,GAAW,EAAK,SAAS,WAAW,EAAU,IAC9C,EAAY,EAAS,UACrB,EAAc,KAAK,aAAa,GAChC,EAAc,GAAI,GAAK,OACvB,EAAkB,KAAK,qBAAqB,GAC5C,EAAQ,OAAO,KAAK,GACpB,EAAc,EAAM,OAGpB,EAAa,KAAK,QAAQ,GAAW,OAAS,EAC9C,EAAW,KAAK,WAAW,EAAS,QAAQ,OAAS,EAEhD,EAAI,EAAG,EAAI,EAAa,IAAK,CACpC,GAAI,GAAO,EAAM,GACb,EAAK,EAAgB,GACrB,EAAY,KAAK,cAAc,GAAM,OACrC,EAAK,EAAO,EAEhB,AAAI,EAAa,KAAU,OACzB,GAAM,EAAK,IAAI,KAAK,cAAc,GAAO,KAAK,eAC9C,EAAa,GAAQ,GAErB,EAAM,EAAa,GAGrB,EAAQ,EAAQ,OAAK,IAAM,GAAK,GAAO,MAAK,IAAO,GAAI,KAAK,GAAK,KAAK,GAAM,GAAc,KAAK,mBAAmB,KAAe,GACjI,GAAS,EACT,GAAS,EACT,EAAqB,KAAK,MAAM,EAAQ,KAAQ,IAQhD,EAAY,OAAO,EAAW,GAGhC,EAAa,GAAY,EAG3B,KAAK,aAAe,GAQtB,EAAK,QAAQ,UAAU,eAAiB,UAAY,CAClD,KAAK,SAAW,EAAK,SAAS,UAC5B,OAAO,KAAK,KAAK,eAAe,SAYpC,EAAK,QAAQ,UAAU,MAAQ,UAAY,CACzC,YAAK,+BACL,KAAK,qBACL,KAAK,iBAEE,GAAI,GAAK,MAAM,CACpB,cAAe,KAAK,cACpB,aAAc,KAAK,aACnB,SAAU,KAAK,SACf,OAAQ,OAAO,KAAK,KAAK,SACzB,SAAU,KAAK,kBAkBnB,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAI,CACzC,GAAI,GAAO,MAAM,UAAU,MAAM,KAAK,UAAW,GACjD,EAAK,QAAQ,MACb,EAAG,MAAM,KAAM,IAcjB,EAAK,UAAY,SAAU,EAAM,EAAO,EAAU,CAShD,OARI,GAAiB,OAAO,OAAO,MAC/B,EAAe,OAAO,KAAK,GAAY,IAOlC,EAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,GAAI,GAAM,EAAa,GACvB,EAAe,GAAO,EAAS,GAAK,QAGtC,KAAK,SAAW,OAAO,OAAO,MAE1B,IAAS,QACX,MAAK,SAAS,GAAQ,OAAO,OAAO,MACpC,KAAK,SAAS,GAAM,GAAS,IAajC,EAAK,UAAU,UAAU,QAAU,SAAU,EAAgB,CAG3D,OAFI,GAAQ,OAAO,KAAK,EAAe,UAE9B,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GACb,EAAS,OAAO,KAAK,EAAe,SAAS,IAEjD,AAAI,KAAK,SAAS,IAAS,MACzB,MAAK,SAAS,GAAQ,OAAO,OAAO,OAGtC,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAQ,EAAO,GACf,EAAO,OAAO,KAAK,EAAe,SAAS,GAAM,IAErD,AAAI,KAAK,SAAS,GAAM,IAAU,MAChC,MAAK,SAAS,GAAM,GAAS,OAAO,OAAO,OAG7C,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAM,EAAK,GAEf,AAAI,KAAK,SAAS,GAAM,GAAO,IAAQ,KACrC,KAAK,SAAS,GAAM,GAAO,GAAO,EAAe,SAAS,GAAM,GAAO,GAEvE,KAAK,SAAS,GAAM,GAAO,GAAO,KAAK,SAAS,GAAM,GAAO,GAAK,OAAO,EAAe,SAAS,GAAM,GAAO,QAexH,EAAK,UAAU,UAAU,IAAM,SAAU,EAAM,EAAO,EAAU,CAC9D,GAAI,CAAE,KAAQ,MAAK,UAAW,CAC5B,KAAK,SAAS,GAAQ,OAAO,OAAO,MACpC,KAAK,SAAS,GAAM,GAAS,EAC7B,OAGF,GAAI,CAAE,KAAS,MAAK,SAAS,IAAQ,CACnC,KAAK,SAAS,GAAM,GAAS,EAC7B,OAKF,OAFI,GAAe,OAAO,KAAK,GAEtB,EAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,GAAI,GAAM,EAAa,GAEvB,AAAI,IAAO,MAAK,SAAS,GAAM,GAC7B,KAAK,SAAS,GAAM,GAAO,GAAO,KAAK,SAAS,GAAM,GAAO,GAAK,OAAO,EAAS,IAElF,KAAK,SAAS,GAAM,GAAO,GAAO,EAAS,KAejD,EAAK,MAAQ,SAAU,EAAW,CAChC,KAAK,QAAU,GACf,KAAK,UAAY,GA2BnB,EAAK,MAAM,SAAW,GAAI,QAAQ,KAClC,EAAK,MAAM,SAAS,KAAO,EAC3B,EAAK,MAAM,SAAS,QAAU,EAC9B,EAAK,MAAM,SAAS,SAAW,EAa/B,EAAK,MAAM,SAAW,CAIpB,SAAU,EAMV,SAAU,EAMV,WAAY,GA0Bd,EAAK,MAAM,UAAU,OAAS,SAAU,EAAQ,CAC9C,MAAM,UAAY,IAChB,GAAO,OAAS,KAAK,WAGjB,SAAW,IACf,GAAO,MAAQ,GAGX,eAAiB,IACrB,GAAO,YAAc,IAGjB,YAAc,IAClB,GAAO,SAAW,EAAK,MAAM,SAAS,MAGnC,EAAO,SAAW,EAAK,MAAM,SAAS,SAAa,EAAO,KAAK,OAAO,IAAM,EAAK,MAAM,UAC1F,GAAO,KAAO,IAAM,EAAO,MAGxB,EAAO,SAAW,EAAK,MAAM,SAAS,UAAc,EAAO,KAAK,MAAM,KAAO,EAAK,MAAM,UAC3F,GAAO,KAAO,GAAK,EAAO,KAAO,KAG7B,YAAc,IAClB,GAAO,SAAW,EAAK,MAAM,SAAS,UAGxC,KAAK,QAAQ,KAAK,GAEX,MAUT,EAAK,MAAM,UAAU,UAAY,UAAY,CAC3C,OAAS,GAAI,EAAG,EAAI,KAAK,QAAQ,OAAQ,IACvC,GAAI,KAAK,QAAQ,GAAG,UAAY,EAAK,MAAM,SAAS,WAClD,MAAO,GAIX,MAAO,IA6BT,EAAK,MAAM,UAAU,KAAO,SAAU,EAAM,EAAS,CACnD,GAAI,MAAM,QAAQ,GAChB,SAAK,QAAQ,SAAU,EAAG,CAAE,KAAK,KAAK,EAAG,EAAK,MAAM,MAAM,KAAa,MAChE,KAGT,GAAI,GAAS,GAAW,GACxB,SAAO,KAAO,EAAK,WAEnB,KAAK,OAAO,GAEL,MAET,EAAK,gBAAkB,SAAU,EAAS,EAAO,EAAK,CACpD,KAAK,KAAO,kBACZ,KAAK,QAAU,EACf,KAAK,MAAQ,EACb,KAAK,IAAM,GAGb,EAAK,gBAAgB,UAAY,GAAI,OACrC,EAAK,WAAa,SAAU,EAAK,CAC/B,KAAK,QAAU,GACf,KAAK,IAAM,EACX,KAAK,OAAS,EAAI,OAClB,KAAK,IAAM,EACX,KAAK,MAAQ,EACb,KAAK,oBAAsB,IAG7B,EAAK,WAAW,UAAU,IAAM,UAAY,CAG1C,OAFI,GAAQ,EAAK,WAAW,QAErB,GACL,EAAQ,EAAM,OAIlB,EAAK,WAAW,UAAU,YAAc,UAAY,CAKlD,OAJI,GAAY,GACZ,EAAa,KAAK,MAClB,EAAW,KAAK,IAEX,EAAI,EAAG,EAAI,KAAK,oBAAoB,OAAQ,IACnD,EAAW,KAAK,oBAAoB,GACpC,EAAU,KAAK,KAAK,IAAI,MAAM,EAAY,IAC1C,EAAa,EAAW,EAG1B,SAAU,KAAK,KAAK,IAAI,MAAM,EAAY,KAAK,MAC/C,KAAK,oBAAoB,OAAS,EAE3B,EAAU,KAAK,KAGxB,EAAK,WAAW,UAAU,KAAO,SAAU,EAAM,CAC/C,KAAK,QAAQ,KAAK,CAChB,KAAM,EACN,IAAK,KAAK,cACV,MAAO,KAAK,MACZ,IAAK,KAAK,MAGZ,KAAK,MAAQ,KAAK,KAGpB,EAAK,WAAW,UAAU,gBAAkB,UAAY,CACtD,KAAK,oBAAoB,KAAK,KAAK,IAAM,GACzC,KAAK,KAAO,GAGd,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,GAAI,KAAK,KAAO,KAAK,OACnB,MAAO,GAAK,WAAW,IAGzB,GAAI,GAAO,KAAK,IAAI,OAAO,KAAK,KAChC,YAAK,KAAO,EACL,GAGT,EAAK,WAAW,UAAU,MAAQ,UAAY,CAC5C,MAAO,MAAK,IAAM,KAAK,OAGzB,EAAK,WAAW,UAAU,OAAS,UAAY,CAC7C,AAAI,KAAK,OAAS,KAAK,KACrB,MAAK,KAAO,GAGd,KAAK,MAAQ,KAAK,KAGpB,EAAK,WAAW,UAAU,OAAS,UAAY,CAC7C,KAAK,KAAO,GAGd,EAAK,WAAW,UAAU,eAAiB,UAAY,CACrD,GAAI,GAAM,EAEV,EACE,GAAO,KAAK,OACZ,EAAW,EAAK,WAAW,SACpB,EAAW,IAAM,EAAW,IAErC,AAAI,GAAQ,EAAK,WAAW,KAC1B,KAAK,UAIT,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,MAAO,MAAK,IAAM,KAAK,QAGzB,EAAK,WAAW,IAAM,MACtB,EAAK,WAAW,MAAQ,QACxB,EAAK,WAAW,KAAO,OACvB,EAAK,WAAW,cAAgB,gBAChC,EAAK,WAAW,MAAQ,QACxB,EAAK,WAAW,SAAW,WAE3B,EAAK,WAAW,SAAW,SAAU,EAAO,CAC1C,SAAM,SACN,EAAM,KAAK,EAAK,WAAW,OAC3B,EAAM,SACC,EAAK,WAAW,SAGzB,EAAK,WAAW,QAAU,SAAU,EAAO,CAQzC,GAPI,EAAM,QAAU,GAClB,GAAM,SACN,EAAM,KAAK,EAAK,WAAW,OAG7B,EAAM,SAEF,EAAM,OACR,MAAO,GAAK,WAAW,SAI3B,EAAK,WAAW,gBAAkB,SAAU,EAAO,CACjD,SAAM,SACN,EAAM,iBACN,EAAM,KAAK,EAAK,WAAW,eACpB,EAAK,WAAW,SAGzB,EAAK,WAAW,SAAW,SAAU,EAAO,CAC1C,SAAM,SACN,EAAM,iBACN,EAAM,KAAK,EAAK,WAAW,OACpB,EAAK,WAAW,SAGzB,EAAK,WAAW,OAAS,SAAU,EAAO,CACxC,AAAI,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,OAe/B,EAAK,WAAW,cAAgB,EAAK,UAAU,UAE/C,EAAK,WAAW,QAAU,SAAU,EAAO,CACzC,OAAa,CACX,GAAI,GAAO,EAAM,OAEjB,GAAI,GAAQ,EAAK,WAAW,IAC1B,MAAO,GAAK,WAAW,OAIzB,GAAI,EAAK,WAAW,IAAM,GAAI,CAC5B,EAAM,kBACN,SAGF,GAAI,GAAQ,IACV,MAAO,GAAK,WAAW,SAGzB,GAAI,GAAQ,IACV,SAAM,SACF,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,MAEtB,EAAK,WAAW,gBAGzB,GAAI,GAAQ,IACV,SAAM,SACF,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,MAEtB,EAAK,WAAW,SAczB,GARI,GAAQ,KAAO,EAAM,UAAY,GAQjC,GAAQ,KAAO,EAAM,UAAY,EACnC,SAAM,KAAK,EAAK,WAAW,UACpB,EAAK,WAAW,QAGzB,GAAI,EAAK,MAAM,EAAK,WAAW,eAC7B,MAAO,GAAK,WAAW,UAK7B,EAAK,YAAc,SAAU,EAAK,EAAO,CACvC,KAAK,MAAQ,GAAI,GAAK,WAAY,GAClC,KAAK,MAAQ,EACb,KAAK,cAAgB,GACrB,KAAK,UAAY,GAGnB,EAAK,YAAY,UAAU,MAAQ,UAAY,CAC7C,KAAK,MAAM,MACX,KAAK,QAAU,KAAK,MAAM,QAI1B,OAFI,GAAQ,EAAK,YAAY,YAEtB,GACL,EAAQ,EAAM,MAGhB,MAAO,MAAK,OAGd,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,MAAO,MAAK,QAAQ,KAAK,YAG3B,EAAK,YAAY,UAAU,cAAgB,UAAY,CACrD,GAAI,GAAS,KAAK,aAClB,YAAK,WAAa,EACX,GAGT,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,GAAI,GAAkB,KAAK,cAC3B,KAAK,MAAM,OAAO,GAClB,KAAK,cAAgB,IAGvB,EAAK,YAAY,YAAc,SAAU,EAAQ,CAC/C,GAAI,GAAS,EAAO,aAEpB,GAAI,GAAU,KAId,OAAQ,EAAO,UACR,GAAK,WAAW,SACnB,MAAO,GAAK,YAAY,kBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,4CAA8C,EAAO,KAExE,KAAI,GAAO,IAAI,QAAU,GACvB,IAAgB,gBAAkB,EAAO,IAAM,KAG3C,GAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,OAIzE,EAAK,YAAY,cAAgB,SAAU,EAAQ,CACjD,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,QAAQ,EAAO,SACR,IACH,EAAO,cAAc,SAAW,EAAK,MAAM,SAAS,WACpD,UACG,IACH,EAAO,cAAc,SAAW,EAAK,MAAM,SAAS,SACpD,cAEA,GAAI,GAAe,kCAAoC,EAAO,IAAM,IACpE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGvE,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,GAAI,GAAe,yCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,OAAQ,EAAW,UACZ,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,mCAAqC,EAAW,KAAO,IAC1E,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,WAAa,SAAU,EAAQ,CAC9C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,EAAO,MAAM,UAAU,QAAQ,EAAO,MAAQ,GAAI,CACpD,GAAI,GAAiB,EAAO,MAAM,UAAU,IAAI,SAAU,EAAG,CAAE,MAAO,IAAM,EAAI,MAAO,KAAK,MACxF,EAAe,uBAAyB,EAAO,IAAM,uBAAyB,EAElF,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,OAAS,CAAC,EAAO,KAEtC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,GAAI,GAAe,gCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,0BAA4B,EAAW,KAAO,IACjE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,UAAY,SAAU,EAAQ,CAC7C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,GAAO,cAAc,KAAO,EAAO,IAAI,cAEnC,EAAO,IAAI,QAAQ,MAAQ,IAC7B,GAAO,cAAc,YAAc,IAGrC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,kBAAoB,SAAU,EAAQ,CACrD,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,GAAe,SAAS,EAAO,IAAK,IAExC,GAAI,MAAM,GAAe,CACvB,GAAI,GAAe,gCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,aAAe,EAEpC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,WAAa,SAAU,EAAQ,CAC9C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,GAAQ,SAAS,EAAO,IAAK,IAEjC,GAAI,MAAM,GAAQ,CAChB,GAAI,GAAe,wBACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,MAAQ,EAE7B,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAQ7E,SAAU,EAAM,EAAS,CACzB,AAAI,MAAO,SAAW,YAAc,OAAO,IAEzC,OAAO,GACF,AAAI,MAAO,KAAY,SAM5B,GAAO,QAAU,IAGjB,EAAK,KAAO,KAEd,KAAM,UAAY,CAMlB,MAAO,WCh5GX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAQA,aAOA,GAAI,IAAkB,UAOtB,GAAO,QAAU,GAUjB,YAAoB,EAAQ,CAC1B,GAAI,GAAM,GAAK,EACX,EAAQ,GAAgB,KAAK,GAEjC,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,GACA,EAAO,GACP,EAAQ,EACR,EAAY,EAEhB,IAAK,EAAQ,EAAM,MAAO,EAAQ,EAAI,OAAQ,IAAS,CACrD,OAAQ,EAAI,WAAW,QAChB,IACH,EAAS,SACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,OACT,UACG,IACH,EAAS,OACT,cAEA,SAGJ,AAAI,IAAc,GAChB,IAAQ,EAAI,UAAU,EAAW,IAGnC,EAAY,EAAQ,EACpB,GAAQ,EAGV,MAAO,KAAc,EACjB,EAAO,EAAI,UAAU,EAAW,GAChC,KCtDN,OAAiB,QCAjB,OAAuB,OAiChB,YACL,EACmB,CACnB,GAAM,GAAY,GAAI,KAChB,EAAY,GAAI,KACtB,OAAW,KAAO,GAAM,CACtB,GAAM,CAAC,EAAM,GAAQ,EAAI,SAAS,MAAM,KAGlC,EAAW,EAAI,SACf,EAAW,EAAI,MAGf,EAAO,eAAW,EAAI,MACzB,QAAQ,mBAAoB,IAC5B,QAAQ,OAAQ,KAGnB,GAAI,EAAM,CACR,GAAM,GAAS,EAAU,IAAI,GAG7B,AAAK,EAAQ,IAAI,GASf,EAAU,IAAI,EAAU,CACtB,WACA,QACA,OACA,WAZF,GAAO,MAAQ,EAAI,MACnB,EAAO,KAAQ,EAGf,EAAQ,IAAI,QAcd,GAAU,IAAI,EAAU,CACtB,WACA,QACA,SAIN,MAAO,GCjFT,OAAuB,OAsChB,YACL,EAA2B,EACD,CAC1B,GAAM,GAAY,GAAI,QAAO,EAAO,UAAW,OACzC,EAAY,CAAC,EAAY,EAAc,IACpC,GAAG,4BAA+B,WAI3C,MAAO,AAAC,IAAkB,CACxB,EAAQ,EACL,QAAQ,gBAAiB,KACzB,OAGH,GAAM,GAAQ,GAAI,QAAO,MAAM,EAAO,cACpC,EACG,QAAQ,uBAAwB,QAChC,QAAQ,EAAW,QACnB,OAGL,MAAO,IACL,GACI,eAAW,GACX,GAED,QAAQ,EAAO,GACf,QAAQ,8BAA+B,OCpCzC,YACL,EACqB,CACrB,GAAM,GAAS,GAAK,MAAa,MAAM,CAAC,QAAS,SAIjD,MAHe,IAAK,MAAa,YAAY,EAAO,GAG7C,QACA,EAAM,QAWR,YACL,EAA4B,EACV,CAClB,GAAM,GAAU,GAAI,KAAuB,GAGrC,EAA2B,GACjC,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,OAAW,KAAU,GACnB,AAAI,EAAM,GAAG,WAAW,EAAO,OAC7B,GAAO,EAAO,MAAQ,GACtB,EAAQ,OAAO,IAIrB,OAAW,KAAU,GACnB,EAAO,EAAO,MAAQ,GAGxB,MAAO,GC4BT,YAAoB,EAAa,EAAuB,CACtD,GAAM,CAAC,EAAG,GAAK,CAAC,GAAI,KAAI,GAAI,GAAI,KAAI,IACpC,MAAO,CACL,GAAG,GAAI,KAAI,CAAC,GAAG,GAAG,OAAO,GAAS,CAAC,EAAE,IAAI,MAWtC,WAAa,CAgCX,YAAY,CAAE,SAAQ,OAAM,QAAO,WAAwB,CAChE,KAAK,QAAU,EAGf,KAAK,UAAY,GAAuB,GACxC,KAAK,UAAY,GAAuB,EAAQ,IAGhD,KAAK,UAAU,UAAY,GAAI,QAAO,EAAO,WAG7C,AAAI,MAAO,IAAU,YACnB,KAAK,MAAQ,KAAK,UAAY,CAG5B,AAAI,EAAO,KAAK,SAAW,GAAK,EAAO,KAAK,KAAO,KACjD,KAAK,IAAK,KAAa,EAAO,KAAK,KAC1B,EAAO,KAAK,OAAS,GAC9B,KAAK,IAAK,KAAa,cAAc,GAAG,EAAO,OAIjD,GAAM,GAAM,GAAW,CACrB,UAAW,iBAAkB,WAC5B,EAAQ,UAGX,OAAW,KAAQ,GAAO,KAAK,IAAI,GACjC,IAAa,KAAO,KAAQ,KAAa,IAEzC,OAAW,KAAM,GACf,KAAK,SAAS,OAAO,EAAK,IAC1B,KAAK,eAAe,OAAO,EAAK,IAKpC,KAAK,IAAI,YAGT,KAAK,MAAM,QAAS,CAAE,MAAO,MAC7B,KAAK,MAAM,QAGX,OAAW,KAAO,GAChB,KAAK,IAAI,KAKb,KAAK,MAAQ,KAAK,MAAM,KAAK,GAoB1B,OAAO,EAA6B,CACzC,GAAI,EACF,GAAI,CACF,GAAM,GAAY,KAAK,UAAU,GAG3B,EAAU,GAAiB,GAC9B,OAAO,GACN,EAAO,WAAa,KAAK,MAAM,SAAS,YAItC,EAAS,KAAK,MAAM,OAAO,GAAG,MAGjC,OAAyB,CAAC,EAAM,CAAE,MAAK,QAAO,eAAgB,CAC7D,GAAM,GAAW,KAAK,UAAU,IAAI,GACpC,GAAI,MAAO,IAAa,YAAa,CACnC,GAAM,CAAE,WAAU,QAAO,OAAM,UAAW,EAGpC,EAAQ,GACZ,EACA,OAAO,KAAK,EAAU,WAIlB,EAAQ,CAAC,CAAC,EAAS,EAAC,OAAO,OAAO,GAAO,MAAM,GAAK,GAC1D,EAAK,KAAK,CACR,WACA,MAAO,EAAU,GACjB,KAAO,EAAU,GACjB,MAAO,EAAS,GAAI,GACpB,UAGJ,MAAO,IACN,IAGF,KAAK,CAAC,EAAG,IAAM,EAAE,MAAQ,EAAE,OAG3B,OAAO,CAAC,EAAO,IAAW,CACzB,GAAM,GAAW,KAAK,UAAU,IAAI,EAAO,UAC3C,GAAI,MAAO,IAAa,YAAa,CACnC,GAAM,GAAM,UAAY,GACpB,EAAS,OAAQ,SACjB,EAAS,SACb,EAAM,IAAI,EAAK,CAAC,GAAG,EAAM,IAAI,IAAQ,GAAI,IAE3C,MAAO,IACN,GAAI,MAGL,EACJ,GAAI,KAAK,QAAQ,YAAa,CAC5B,GAAM,GAAS,KAAK,MAAM,MAAM,GAAW,CACzC,OAAW,KAAU,GACnB,EAAQ,KAAK,EAAO,KAAM,CACxB,OAAQ,CAAC,SACT,SAAU,KAAK,MAAM,SAAS,SAC9B,SAAU,KAAK,MAAM,SAAS,aAKpC,EAAc,EAAO,OACjB,OAAO,KAAK,EAAO,GAAG,UAAU,UAChC,GAIN,MAAO,IACL,MAAO,CAAC,GAAG,EAAO,WACf,MAAO,IAAgB,aAAe,CAAE,sBAIvC,EAAN,CACA,QAAQ,KAAK,kBAAkB,uCAKnC,MAAO,CAAE,MAAO,MChSb,GAAW,GAAX,UAAW,EAAX,CACL,qBACA,qBACA,qBACA,yBAJgB,WLwBlB,GAAI,GAqBJ,YACE,EACe,gCACf,GAAI,GAAO,UAGX,GAAI,MAAO,SAAW,aAAe,gBAAkB,QAAQ,CAC7D,GAAM,GAAS,SAAS,cAAiC,eACnD,CAAC,GAAQ,EAAO,IAAI,MAAM,WAGhC,EAAO,EAAK,QAAQ,KAAM,GAI5B,GAAM,GAAU,GAChB,OAAW,KAAQ,GAAO,KAAM,CAC9B,OAAQ,OAGD,KACH,EAAQ,KAAK,GAAG,gBAChB,UAGG,SACA,KACH,EAAQ,KAAK,GAAG,gBAChB,MAIJ,AAAI,IAAS,MACX,EAAQ,KAAK,GAAG,cAAiB,YAIrC,AAAI,EAAO,KAAK,OAAS,GACvB,EAAQ,KAAK,GAAG,2BAGd,EAAQ,QACV,MAAM,eACJ,GAAG,oCACH,GAAG,MAeT,YACE,EACwB,gCACxB,OAAQ,EAAQ,UAGT,GAAkB,MACrB,YAAM,IAAqB,EAAQ,KAAK,QACxC,EAAQ,GAAI,GAAO,EAAQ,MACpB,CACL,KAAM,EAAkB,WAIvB,GAAkB,MACrB,MAAO,CACL,KAAM,EAAkB,OACxB,KAAM,EAAQ,EAAM,OAAO,EAAQ,MAAQ,CAAE,MAAO,aAKtD,KAAM,IAAI,WAAU,2BAS1B,KAAK,KAAO,WAGZ,iBAAiB,UAAW,AAAM,GAAM,0BACtC,YAAY,KAAM,IAAQ,EAAG", + "names": [] +} diff --git a/assets/stylesheets/main.802231af.min.css b/assets/stylesheets/main.802231af.min.css new file mode 100644 index 0000000..f9d72c0 --- /dev/null +++ b/assets/stylesheets/main.802231af.min.css @@ -0,0 +1,2 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-default-fg-color:rgba(0,0,0,0.87);--md-default-fg-color--light:rgba(0,0,0,0.54);--md-default-fg-color--lighter:rgba(0,0,0,0.32);--md-default-fg-color--lightest:rgba(0,0,0,0.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,0.7);--md-default-bg-color--lighter:hsla(0,0%,100%,0.3);--md-default-bg-color--lightest:hsla(0,0%,100%,0.12);--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:hsla(0,0%,100%,0.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}:root>*{--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,0.5);--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-mark-color:rgba(255,255,0,0.5);--md-typeset-del-color:hsla(6,90%,60%,0.15);--md-typeset-ins-color:rgba(11,213,112,0.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,0.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,0.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,0.3);--md-footer-bg-color:rgba(0,0,0,0.87);--md-footer-bg-color--dark:rgba(0,0,0,0.32)}.md-icon svg{fill:currentColor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace}: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:1em 0}.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-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}@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;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{background-color:transparent;box-shadow:none;margin:initial;padding:initial}.md-typeset a code{color:currentColor}.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;overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.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)}@media screen and (max-width:44.9375em){.md-typeset>pre{margin:1em -.8rem}.md-typeset>pre code{border-radius:0}}.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{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:focus:after,.md-typeset abbr[title]:hover:after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;left:0;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-left:0;margin-right:.078125em}.md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter);color:var(--md-default-fg-color--light);padding-left:.6rem}[dir=rtl] .md-typeset blockquote{border-left:initial;border-right:.2rem solid var(--md-default-fg-color--lighter);padding-left:0;padding-right:.6rem}.md-typeset ul{list-style-type:disc}.md-typeset ol,.md-typeset ul{display:flow-root;margin-left:.625em;padding:0}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-left:0;margin-right:.625em}.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}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-left:0;margin-right:1.25em}.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}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin:.5em 0 .5em .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-left:0;margin-right:.625em}.md-typeset dd{margin:1em 0 1.5em 1.875em}[dir=rtl] .md-typeset dd{margin-left:0;margin-right:1.875em}.md-typeset img,.md-typeset svg{height:auto;max-width:100%}.md-typeset img[align=left],.md-typeset svg[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right],.md-typeset svg[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child,.md-typeset svg[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:0 auto;max-width:100%;text-align:center;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto 2em;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]) th a{color:inherit}.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:rgba(0,0,0,.035);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}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;margin-left:.5em;-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%}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.9375em){body[data-md-state=lock]{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;white-space:nowrap}.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}.md-announce{background-color:var(--md-footer-bg-color);overflow:auto}@media print{.md-announce{display:none}}.md-announce__inner{color:var(--md-footer-fg-color);font-size:.7rem;margin:.6rem auto;padding:0 .8rem}: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;position:absolute;right:.5em;top:.5em;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-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)}.md-content{flex-grow:1;overflow:hidden;scroll-padding-top:51.2rem}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){.md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:.8rem;margin-right:1.2rem}.md-sidebar--secondary: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;margin-right:.8rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}.md-content__button{float:right;margin:.4rem 0 .4rem .4rem;padding:0}@media print{.md-content__button{display:none}}[dir=rtl] .md-content__button{float:left;margin-left:0;margin-right:.4rem}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);left:auto;min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;right:.8rem;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:3}@media print{.md-dialog{display:none}}[dir=rtl] .md-dialog{left:.8rem;right:auto}.md-dialog[data-md-state=open]{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-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)}.md-typeset .md-input{border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 .025rem .05rem rgba(0,0,0,.1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{box-shadow:0 .4rem 1rem rgba(0,0,0,.15),0 .025rem .05rem rgba(0,0,0,.15)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);left:0;position:-webkit-sticky;position:sticky;right:0;top:0;z-index:3}@media print{.md-header{display:none}}.md-header[data-md-state=shadow]{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header[data-md-state=hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,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.1875em){.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:1.2rem}@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}.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__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem;margin-left:1rem;margin-right:.4rem}.md-header__title[data-md-state=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[data-md-state=active] .md-header__topic{transform:translateX(1.25rem)}.md-header__title[data-md-state=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__source{display:none}@media screen and (min-width:60em){.md-header__source{display:block;margin-left:1rem;max-width:11.7rem;width:11.7rem}[dir=rtl] .md-header__source{margin-left:0;margin-right:1rem}}@media screen and (min-width:76.25em){.md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{overflow:auto;padding:.2rem}.md-footer__link{display:flex;outline-color:var(--md-accent-fg-color);padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}@media screen and (min-width:45em){.md-footer__link{width:50%}}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}.md-footer__link--prev{float:left}@media screen and (max-width:44.9375em){.md-footer__link--prev{width:25%}.md-footer__link--prev .md-footer__title{display:none}}[dir=rtl] .md-footer__link--prev{float:right}[dir=rtl] .md-footer__link--prev svg{transform:scaleX(-1)}.md-footer__link--next{float:right;text-align:right}@media screen and (max-width:44.9375em){.md-footer__link--next{width:75%}}[dir=rtl] .md-footer__link--next{float:left;text-align:left}[dir=rtl] .md-footer__link--next svg{transform:scaleX(-1)}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.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-footer-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-footer-copyright{width:auto}}.md-footer-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-footer-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-footer-social{padding:.6rem 0}}.md-footer-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-footer-social__link:before{line-height:1.9}.md-footer-social__link svg{fill:currentColor;max-height:.8rem;vertical-align:-25%}: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{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;width:2.4rem}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}.md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0;padding-right:.6rem}.md-nav__link{cursor:pointer;display:block;margin-top:.625em;overflow:hidden;scroll-snap-align:start;text-overflow:ellipsis;transition:color 125ms}.md-nav__link[data-md-state=blur]{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__item--nested>.md-nav__link{color:inherit}.md-nav__link:focus,.md-nav__link:hover{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__source{display:none}@media screen and (max-width:76.1875em){.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;font-weight:400;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;left:.4rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{left:auto;right:.4rem}.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-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;-ms-scroll-snap-type:y mandatory;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)}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;top:.2rem}[dir=rtl] .md-nav--primary .md-nav__title .md-logo{left:auto;right:.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);padding:0}.md-nav--primary .md-nav__item--nested>.md-nav__link{padding-right:2.4rem}[dir=rtl] .md-nav--primary .md-nav__item--nested>.md-nav__link{padding-left:2.4rem;padding-right:.8rem}.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;position:relative}.md-nav--primary .md-nav__link .md-nav__icon{color:inherit;font-size:1.2rem;height:1.2rem;margin-top:-.6rem;position:absolute;right:.6rem;top:50%;width:1.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{left:.6rem;right:auto}.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-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__link{position:static}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}.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-left:0;padding-right:1.4rem}.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-left:0;padding-right:2rem}.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-left:0;padding-right:2.6rem}.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-left:0;padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.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.9375em){.md-nav--primary .md-nav__link[for=__toc]{display:block;padding-right:2.4rem}[dir=rtl] .md-nav--primary .md-nav__link[for=__toc]{padding-left:2.4rem;padding-right:.8rem}.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.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:block;padding-right:2.4rem;scroll-snap-align:none}[dir=rtl] .md-nav--integrated .md-nav__link[for=__toc]{padding-left:2.4rem;padding-right:.8rem}.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--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:checked~.md-nav,.md-nav__toggle:indeterminate~.md-nav{display:block}.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{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__title{display:block;padding:0;pointer-events:none;scroll-snap-align:start}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{float:right;height:.9rem;transition:transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{float:left;transform:rotate(180deg)}.md-nav__icon:after{background-color:currentColor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav>.md-nav__title{display:block;padding:0 .6rem;pointer-events:none;scroll-snap-align:start}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}.md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{border-left:.05rem solid var(--md-primary-fg-color);display:block;margin-bottom:1.25em}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav>.md-nav__title{display:none}}: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.9375em){.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;left:-2.2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[dir=rtl] .md-search__overlay{left:auto;right:-2.2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;left:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[dir=rtl] .md-search__overlay{left:auto;right: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.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[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.9375em){.md-search__inner{height:100%;left:100%;opacity:0;position:fixed;top:0;transform:translateX(5%);transition:right 0ms .3s,left 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:100%;z-index:2}[data-md-toggle=search]:checked~.md-header .md-search__inner{left:0;opacity:1;transform:translateX(0);transition:right 0ms 0ms,left 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s}[dir=rtl] [data-md-toggle=search]:checked~.md-header .md-search__inner{left:auto;right:0}html [dir=rtl] .md-search__inner{left:auto;right:100%;transform:translateX(-5%)}}@media screen and (min-width:60em){.md-search__inner{float:right;padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}[dir=rtl] .md-search__inner{float:left}}@media screen and (min-width:60em) and (max-width:76.1875em){[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 transparent;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:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[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 rgba(0,0,0,.07);color:var(--md-default-fg-color)}.md-search__input{background:transparent;font-size:.9rem;height:100%;padding:0 2.2rem 0 3.6rem;position:relative;text-overflow:ellipsis;width:100%;z-index:2}[dir=rtl] .md-search__input{padding:0 3.6rem 0 2.2rem}.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::-ms-input-placeholder{-ms-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-webkit-input-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}.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.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){.md-search__input{color:inherit;font-size:.8rem;padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input::-webkit-input-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-primary-bg-color--light)}.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::-webkit-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.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}.md-search__icon[for=__search]{left:.5rem;position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search]{left:auto;right:.5rem}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){.md-search__icon[for=__search]{left:.8rem;top:.6rem}[dir=rtl] .md-search__icon[for=__search]{left:auto;right:.8rem}.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}}.md-search__options{pointer-events:none;position:absolute;right:.5rem;top:.3rem;z-index:2}[dir=rtl] .md-search__options{left:.5rem;right:auto}@media screen and (max-width:59.9375em){.md-search__options{right:.8rem;top:.6rem}[dir=rtl] .md-search__options{left:.8rem;right:auto}}.md-search__options>*{color:var(--md-default-fg-color--light);margin-left:.2rem;opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;padding:0 2.2rem 0 3.6rem;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}[dir=rtl] .md-search__suggest{padding:0 3.6rem 0 2.2rem}@media screen and (min-width:60em){.md-search__suggest{font-size:.8rem;padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}.md-search__output{border-radius:0 0 .1rem .1rem;overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.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:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);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.1875em){.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) transparent;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) transparent}.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){.md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-left:0;padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0}.md-search-result__item{box-shadow:0 -.05rem 0 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{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){.md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-left:.8rem;padding-right:2.2rem}}.md-search-result__more summary:focus,.md-search-result__more summary:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::-webkit-details-marker,.md-search-result__more summary::marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){.md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-left:.8rem;padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;left:0;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.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-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon{left:auto;right:0}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:transparent;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);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 transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;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}.md-select__link{cursor:pointer;display:block;outline:none;padding-left:.6rem;padding-right:1.2rem;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.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:-webkit-sticky;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;left:-12.1rem;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:4}[dir=rtl] .md-sidebar--primary{left:auto;right:-12.1rem}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);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;-ms-scroll-snap-type:none;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}}.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{-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:4}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@-webkit-keyframes facts{0%{height:0}to{height:.65rem}}@keyframes facts{0%{height:0}to{height:.65rem}}@-webkit-keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}@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}.md-source__icon svg{margin-left:.6rem;margin-top:.6rem}[dir=rtl] .md-source__icon svg{margin-left:0;margin-right:.6rem}.md-source__icon+.md-source__repository{margin-left:-2rem;padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-left:0;margin-right:-2rem;padding-left:0;padding-right:2rem}.md-source__repository{display:inline-block;margin-left:.6rem;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{font-size:.55rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0}[data-md-state=done] .md-source__facts{-webkit-animation:facts .25s ease-in;animation:facts .25s ease-in}.md-source__fact{display:inline-block}[data-md-state=done] .md-source__fact{-webkit-animation:fact .4s ease-out;animation:fact .4s ease-out}.md-source__fact:before{background-color:currentColor;content:"";display:inline-block;height:.6rem;margin-right:.1rem;-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):before{margin-left:.4rem}[dir=rtl] .md-source__fact{margin-left:.1rem;margin-right:0}[dir=rtl] .md-source__fact:nth-child(1n+2):before{margin-left:0;margin-right:.4rem}.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-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);overflow:auto;width:100%}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[data-md-state=hidden]{pointer-events:none}.md-tabs__list{contain:content;list-style:none;margin:0 0 0 .2rem;padding:0;white-space:nowrap}[dir=rtl] .md-tabs__list{margin-left:0;margin-right:.2rem}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;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--active,.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}.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[data-md-state=hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);color:var(--md-default-fg-color--light);font-size:.7rem;margin-left:50%;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{float:left}.md-top[data-md-state=hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}.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}@-webkit-keyframes hoverfix{0%{pointer-events:none}}@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}.md-version__current{color:inherit;cursor:pointer;margin-left:1.4rem;margin-right:.4rem;outline:none;position:relative;top:.05rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current:after{background-color:currentColor;content:"";display:inline-block;height:.6rem;margin-left:.4rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;width:.4rem}[dir=rtl] .md-version__current:after{margin-left:0;margin-right:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:1}.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 (pointer:coarse){.md-version:hover .md-version__list{-webkit-animation:hoverfix .25s forwards;animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{-webkit-animation:none;animation:none}}.md-version__item{line-height:1.8rem}.md-version__link{cursor:pointer;display:block;outline:none;padding-left:.6rem;padding-right:1.2rem;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.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-left:.2rem solid #448aff;border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 .025rem .05rem rgba(0,0,0,.05);color:var(--md-admonition-fg-color);font-size:.64rem;margin:1.5625em 0;overflow:hidden;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}[dir=rtl] .md-typeset .admonition,[dir=rtl] .md-typeset details{border-left:none;border-right:.2rem solid #448aff}.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}.md-typeset .admonition-title,.md-typeset summary{background-color:rgba(68,138,255,.1);border-left:.2rem solid #448aff;font-weight:700;margin:0 -.6rem 0 -.8rem;padding:.4rem .6rem .4rem 2rem;position:relative}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-left:none;border-right:.2rem solid #448aff;margin:0 -.8rem 0 -.6rem;padding:.4rem 2rem .4rem .6rem}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;left:.6rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;width:1rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{left:auto;right:.6rem}.md-typeset .admonition-title+.tabbed-set:last-child,.md-typeset summary+.tabbed-set:last-child{margin-top:0}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:rgba(68,138,255,.1);border-color:#448aff}.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.abstract,.md-typeset .admonition.summary,.md-typeset .admonition.tldr,.md-typeset details.abstract,.md-typeset details.summary,.md-typeset details.tldr{border-color:#00b0ff}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary,.md-typeset .summary>.admonition-title,.md-typeset .summary>summary,.md-typeset .tldr>.admonition-title,.md-typeset .tldr>summary{background-color:rgba(0,176,255,.1);border-color:#00b0ff}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before,.md-typeset .summary>.admonition-title:before,.md-typeset .summary>summary:before,.md-typeset .tldr>.admonition-title:before,.md-typeset .tldr>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.info,.md-typeset .admonition.todo,.md-typeset details.info,.md-typeset details.todo{border-color:#00b8d4}.md-typeset .info>.admonition-title,.md-typeset .info>summary,.md-typeset .todo>.admonition-title,.md-typeset .todo>summary{background-color:rgba(0,184,212,.1);border-color:#00b8d4}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before,.md-typeset .todo>.admonition-title:before,.md-typeset .todo>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.hint,.md-typeset .admonition.important,.md-typeset .admonition.tip,.md-typeset details.hint,.md-typeset details.important,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .hint>.admonition-title,.md-typeset .hint>summary,.md-typeset .important>.admonition-title,.md-typeset .important>summary,.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:rgba(0,191,165,.1);border-color:#00bfa5}.md-typeset .hint>.admonition-title:before,.md-typeset .hint>summary:before,.md-typeset .important>.admonition-title:before,.md-typeset .important>summary:before,.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.check,.md-typeset .admonition.done,.md-typeset .admonition.success,.md-typeset details.check,.md-typeset details.done,.md-typeset details.success{border-color:#00c853}.md-typeset .check>.admonition-title,.md-typeset .check>summary,.md-typeset .done>.admonition-title,.md-typeset .done>summary,.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:rgba(0,200,83,.1);border-color:#00c853}.md-typeset .check>.admonition-title:before,.md-typeset .check>summary:before,.md-typeset .done>.admonition-title:before,.md-typeset .done>summary:before,.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.faq,.md-typeset .admonition.help,.md-typeset .admonition.question,.md-typeset details.faq,.md-typeset details.help,.md-typeset details.question{border-color:#64dd17}.md-typeset .faq>.admonition-title,.md-typeset .faq>summary,.md-typeset .help>.admonition-title,.md-typeset .help>summary,.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:rgba(100,221,23,.1);border-color:#64dd17}.md-typeset .faq>.admonition-title:before,.md-typeset .faq>summary:before,.md-typeset .help>.admonition-title:before,.md-typeset .help>summary:before,.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.attention,.md-typeset .admonition.caution,.md-typeset .admonition.warning,.md-typeset details.attention,.md-typeset details.caution,.md-typeset details.warning{border-color:#ff9100}.md-typeset .attention>.admonition-title,.md-typeset .attention>summary,.md-typeset .caution>.admonition-title,.md-typeset .caution>summary,.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:rgba(255,145,0,.1);border-color:#ff9100}.md-typeset .attention>.admonition-title:before,.md-typeset .attention>summary:before,.md-typeset .caution>.admonition-title:before,.md-typeset .caution>summary:before,.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.fail,.md-typeset .admonition.failure,.md-typeset .admonition.missing,.md-typeset details.fail,.md-typeset details.failure,.md-typeset details.missing{border-color:#ff5252}.md-typeset .fail>.admonition-title,.md-typeset .fail>summary,.md-typeset .failure>.admonition-title,.md-typeset .failure>summary,.md-typeset .missing>.admonition-title,.md-typeset .missing>summary{background-color:rgba(255,82,82,.1);border-color:#ff5252}.md-typeset .fail>.admonition-title:before,.md-typeset .fail>summary:before,.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before,.md-typeset .missing>.admonition-title:before,.md-typeset .missing>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.danger,.md-typeset .admonition.error,.md-typeset details.danger,.md-typeset details.error{border-color:#ff1744}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary,.md-typeset .error>.admonition-title,.md-typeset .error>summary{background-color:rgba(255,23,68,.1);border-color:#ff1744}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before,.md-typeset .error>.admonition-title:before,.md-typeset .error>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:rgba(245,0,87,.1);border-color:#f50057}.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:rgba(124,77,255,.1);border-color:#7c4dff}.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.cite,.md-typeset .admonition.quote,.md-typeset details.cite,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .cite>.admonition-title,.md-typeset .cite>summary,.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:hsla(0,0%,62%,.1);border-color:#9e9e9e}.md-typeset .cite>.admonition-title:before,.md-typeset .cite>summary:before,.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);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}: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}.md-typeset .footnote>ol{margin-left: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: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 .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-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)}.md-typeset [id^="fnref:"]:target{margin-top:-3.4rem;padding-top:3.4rem;scroll-margin-top:0}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset [id^="fn:"]:target{margin-top:-3.45rem;padding-top:3.45rem;scroll-margin-top:0}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;margin-left:.5rem;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}[dir=rtl] .md-typeset .headerlink{margin-left:0;margin-right:.5rem}.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{scroll-margin-top:3.6rem}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{scroll-margin-top:0}.md-typeset h1:target:before,.md-typeset h2:target:before,.md-typeset h3:target:before{content:"";display:block;margin-top:-3.4rem;padding-top:3.4rem}.md-typeset h4:target{scroll-margin-top:0}.md-typeset h4:target:before{content:"";display:block;margin-top:-3.45rem;padding-top:3.45rem}.md-typeset h5:target,.md-typeset h6:target{scroll-margin-top:0}.md-typeset h5:target:before,.md-typeset h6:target:before{content:"";display:block;margin-top:-3.6rem;padding-top:3.6rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin:1em auto!important;padding:0 .8rem;touch-action:auto;width:-webkit-min-content;width:-moz-min-content;width:min-content}.md-typeset .critic.comment,.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{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}.md-typeset details:after{content:"";display:table}.md-typeset summary{border-top-left-radius:.1rem;border-top-right-radius:.1rem;cursor:pointer;display:block;min-height:1rem;padding:.4rem 1.8rem .4rem 2rem}[dir=rtl] .md-typeset summary{padding:.4rem 2.2rem .4rem 1.8rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.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-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;right:.4rem;top:.4rem;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{left:.4rem;right:auto;transform:rotate(180deg)}.md-typeset summary::-webkit-details-marker,.md-typeset summary::marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentColor;max-height:100%;width:1.125em}.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);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.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:-webkit-sticky;position:sticky;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable{display:flow-root;overflow:hidden}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;overflow:hidden}.md-typeset .highlighttable{border-radius:.1rem;direction:ltr;margin:1em 0}.md-typeset .highlighttable code{border-radius:0}@media screen and (max-width:44.9375em){.md-typeset>.highlight{margin:1em -.8rem}.md-typeset>.highlight .hll{margin:0 -.8rem;padding:0 .8rem}.md-typeset>.highlight code{border-radius:0}.md-typeset>.highlighttable{border-radius:0;margin:1em -.8rem}.md-typeset>.highlighttable .hll{margin:0 -.8rem;padding:0 .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{content:"⎇";padding-right:.4em}.md-typeset .keys .key-left-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-left-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-right-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-right-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-left-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-right-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}.md-typeset .tabbed-content{box-shadow:0 -.05rem var(--md-default-fg-color--lightest);display:none;order:99;width:100%}@media print{.md-typeset .tabbed-content{display:block;order:0}}.md-typeset .tabbed-content>.highlight:only-child pre,.md-typeset .tabbed-content>.highlighttable:only-child,.md-typeset .tabbed-content>pre:only-child{margin:0}.md-typeset .tabbed-content>.highlight:only-child pre>code,.md-typeset .tabbed-content>.highlighttable:only-child>code,.md-typeset .tabbed-content>pre:only-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-content>.tabbed-set{margin:0}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:checked+label{border-color:var(--md-accent-fg-color);color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:checked+label+.tabbed-content{display:block}.md-typeset .tabbed-set>input:focus+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-typeset .tabbed-set>input:not(.focus-visible)+label{-webkit-tap-highlight-color:transparent;outline:none}.md-typeset .tabbed-set>label{border-bottom:.1rem solid transparent;color:var(--md-default-fg-color--light);cursor:pointer;font-size:.64rem;font-weight:700;padding:.9375em 1.25em .78125em;transition:color .25s;width:auto;z-index:1}.md-typeset .tabbed-set>label:hover{color:var(--md-accent-fg-color)}: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}.md-typeset .task-list-item [type=checkbox]{left:-2em;position:absolute;top:.45em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{left:auto;right:-2em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;left:-1.5em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}[dir=rtl] .md-typeset .task-list-indicator:before{left:auto;right:-1.5em}.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)}@media screen and (min-width:45em){.md-typeset .inline{float:left;margin-bottom:.8rem;margin-right:.8rem;margin-top:0;width:11.7rem}[dir=rtl] .md-typeset .inline{float:right;margin-left:.8rem;margin-right:0}.md-typeset .inline.end{float:right;margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{float:left;margin-left:0;margin-right:.8rem}} +/*# sourceMappingURL=main.802231af.min.css.map */ \ No newline at end of file diff --git a/assets/stylesheets/main.802231af.min.css.map b/assets/stylesheets/main.802231af.min.css.map new file mode 100644 index 0000000..a609287 --- /dev/null +++ b/assets/stylesheets/main.802231af.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/main/extensions/pymdownx/_keys.scss","src/assets/stylesheets/main.scss","src/assets/stylesheets/main/_reset.scss","src/assets/stylesheets/main/_colors.scss","src/assets/stylesheets/main/_icons.scss","src/assets/stylesheets/main/_typeset.scss","src/assets/stylesheets/utilities/_break.scss","node_modules/material-shadows/material-shadows.scss","src/assets/stylesheets/main/layout/_base.scss","src/assets/stylesheets/main/layout/_announce.scss","src/assets/stylesheets/main/layout/_clipboard.scss","src/assets/stylesheets/main/layout/_content.scss","src/assets/stylesheets/main/layout/_dialog.scss","src/assets/stylesheets/main/layout/_form.scss","src/assets/stylesheets/main/layout/_header.scss","src/assets/stylesheets/main/layout/_footer.scss","src/assets/stylesheets/main/layout/_nav.scss","src/assets/stylesheets/main/layout/_search.scss","src/assets/stylesheets/main/layout/_select.scss","src/assets/stylesheets/main/layout/_sidebar.scss","src/assets/stylesheets/main/layout/_source.scss","src/assets/stylesheets/main/layout/_tabs.scss","src/assets/stylesheets/main/layout/_top.scss","src/assets/stylesheets/main/layout/_version.scss","src/assets/stylesheets/main/extensions/markdown/_admonition.scss","node_modules/material-design-color/material-color.scss","src/assets/stylesheets/main/extensions/markdown/_footnotes.scss","src/assets/stylesheets/main/extensions/markdown/_toc.scss","src/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss","src/assets/stylesheets/main/extensions/pymdownx/_critic.scss","src/assets/stylesheets/main/extensions/pymdownx/_details.scss","src/assets/stylesheets/main/extensions/pymdownx/_emoji.scss","src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss","src/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss","src/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss","src/assets/stylesheets/main/_modifiers.scss"],"names":[],"mappings":"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","file":"src/assets/stylesheets/main.scss","sourcesContent":["////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Keyboard key\n .keys {\n\n // Keyboard key icon\n kbd::before,\n kbd::after {\n position: relative;\n margin: 0;\n color: inherit;\n -moz-osx-font-smoothing: initial;\n -webkit-font-smoothing: initial;\n }\n\n // Surrounding text\n span {\n padding: 0 px2em(3.2px);\n color: var(--md-default-fg-color--light);\n }\n\n // Define keyboard keys with left icon\n @each $name, $code in (\n\n // Modifiers\n \"alt\": \"\\2387\",\n \"left-alt\": \"\\2387\",\n \"right-alt\": \"\\2387\",\n \"command\": \"\\2318\",\n \"left-command\": \"\\2318\",\n \"right-command\": \"\\2318\",\n \"control\": \"\\2303\",\n \"left-control\": \"\\2303\",\n \"right-control\": \"\\2303\",\n \"meta\": \"\\25C6\",\n \"left-meta\": \"\\25C6\",\n \"right-meta\": \"\\25C6\",\n \"option\": \"\\2325\",\n \"left-option\": \"\\2325\",\n \"right-option\": \"\\2325\",\n \"shift\": \"\\21E7\",\n \"left-shift\": \"\\21E7\",\n \"right-shift\": \"\\21E7\",\n \"super\": \"\\2756\",\n \"left-super\": \"\\2756\",\n \"right-super\": \"\\2756\",\n \"windows\": \"\\229E\",\n \"left-windows\": \"\\229E\",\n \"right-windows\": \"\\229E\",\n\n // Other keys\n \"arrow-down\": \"\\2193\",\n \"arrow-left\": \"\\2190\",\n \"arrow-right\": \"\\2192\",\n \"arrow-up\": \"\\2191\",\n \"backspace\": \"\\232B\",\n \"backtab\": \"\\21E4\",\n \"caps-lock\": \"\\21EA\",\n \"clear\": \"\\2327\",\n \"context-menu\": \"\\2630\",\n \"delete\": \"\\2326\",\n \"eject\": \"\\23CF\",\n \"end\": \"\\2913\",\n \"escape\": \"\\238B\",\n \"home\": \"\\2912\",\n \"insert\": \"\\2380\",\n \"page-down\": \"\\21DF\",\n \"page-up\": \"\\21DE\",\n \"print-screen\": \"\\2399\"\n ) {\n .key-#{$name} {\n &::before {\n padding-right: px2em(6.4px);\n content: $code;\n }\n }\n }\n\n // Define keyboard keys with right icon\n @each $name, $code in (\n \"tab\": \"\\21E5\",\n \"num-enter\": \"\\2324\",\n \"enter\": \"\\23CE\"\n ) {\n .key-#{$name} {\n &::after {\n padding-left: px2em(6.4px);\n content: $code;\n }\n }\n }\n }\n}\n","@charset \"UTF-8\";\nhtml {\n box-sizing: border-box;\n text-size-adjust: none;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\nbody {\n margin: 0;\n}\n\na,\nbutton,\nlabel,\ninput {\n -webkit-tap-highlight-color: transparent;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n\nhr {\n display: block;\n box-sizing: content-box;\n height: 0.05rem;\n padding: 0;\n overflow: visible;\n border: 0;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n line-height: 1em;\n}\n\nimg {\n border-style: none;\n}\n\ntable {\n border-collapse: separate;\n border-spacing: 0;\n}\n\ntd,\nth {\n font-weight: 400;\n vertical-align: top;\n}\n\nbutton {\n margin: 0;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n background: transparent;\n border: 0;\n}\n\ninput {\n border: 0;\n outline: none;\n}\n\n:root {\n --md-default-fg-color: hsla(0, 0%, 0%, 0.87);\n --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32);\n --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07);\n --md-default-bg-color: hsla(0, 0%, 100%, 1);\n --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12);\n --md-primary-fg-color: hsla(231, 48%, 48%, 1);\n --md-primary-fg-color--light: hsla(231, 44%, 56%, 1);\n --md-primary-fg-color--dark: hsla(232, 54%, 41%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-accent-fg-color: hsla(231, 99%, 66%, 1);\n --md-accent-fg-color--transparent: hsla(231, 99%, 66%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n:root > * {\n --md-code-fg-color: hsla(200, 18%, 26%, 1);\n --md-code-bg-color: hsla(0, 0%, 96%, 1);\n --md-code-hl-color: hsla(60, 100%, 50%, 0.5);\n --md-code-hl-number-color: hsla(0, 67%, 50%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 47%, 1);\n --md-code-hl-function-color: hsla(291, 45%, 50%, 1);\n --md-code-hl-constant-color: hsla(250, 63%, 60%, 1);\n --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1);\n --md-code-hl-string-color: hsla(150, 63%, 30%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n --md-typeset-color: var(--md-default-fg-color);\n --md-typeset-a-color: var(--md-primary-fg-color);\n --md-typeset-mark-color: hsla(60, 100%, 50%, 0.5);\n --md-typeset-del-color: hsla(6, 90%, 60%, 0.15);\n --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15);\n --md-typeset-kbd-color: hsla(0, 0%, 98%, 1);\n --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);\n --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1);\n --md-typeset-table-color: hsla(0, 0%, 0%, 0.12);\n --md-admonition-fg-color: var(--md-default-fg-color);\n --md-admonition-bg-color: var(--md-default-bg-color);\n --md-footer-fg-color: hsla(0, 0%, 100%, 1);\n --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-footer-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32);\n}\n\n.md-icon svg {\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n fill: currentColor;\n}\n\nbody {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nbody,\ninput {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\", \"liga\";\n font-family: var(--md-text-font-family, _), -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;\n}\n\ncode,\npre,\nkbd {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\";\n font-family: var(--md-code-font-family, _), SFMono-Regular, Consolas, Menlo, monospace;\n}\n\n:root {\n --md-typeset-table-sort-icon: svg-load(\"material/sort.svg\");\n --md-typeset-table-sort-icon--asc: svg-load(\"material/sort-ascending.svg\");\n --md-typeset-table-sort-icon--desc: svg-load(\"material/sort-descending.svg\");\n}\n\n.md-typeset {\n font-size: 0.8rem;\n line-height: 1.6;\n color-adjust: exact;\n}\n@media print {\n .md-typeset {\n font-size: 0.68rem;\n }\n}\n.md-typeset ul,\n.md-typeset ol,\n.md-typeset dl,\n.md-typeset figure,\n.md-typeset blockquote,\n.md-typeset pre {\n margin: 1em 0;\n}\n.md-typeset h1 {\n margin: 0 0 1.25em;\n color: var(--md-default-fg-color--light);\n font-weight: 300;\n font-size: 2em;\n line-height: 1.3;\n letter-spacing: -0.01em;\n}\n.md-typeset h2 {\n margin: 1.6em 0 0.64em;\n font-weight: 300;\n font-size: 1.5625em;\n line-height: 1.4;\n letter-spacing: -0.01em;\n}\n.md-typeset h3 {\n margin: 1.6em 0 0.8em;\n font-weight: 400;\n font-size: 1.25em;\n line-height: 1.5;\n letter-spacing: -0.01em;\n}\n.md-typeset h2 + h3 {\n margin-top: 0.8em;\n}\n.md-typeset h4 {\n margin: 1em 0;\n font-weight: 700;\n letter-spacing: -0.01em;\n}\n.md-typeset h5,\n.md-typeset h6 {\n margin: 1.25em 0;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: 0.8em;\n letter-spacing: -0.01em;\n}\n.md-typeset h5 {\n text-transform: uppercase;\n}\n.md-typeset hr {\n display: flow-root;\n margin: 1.5em 0;\n border-bottom: 0.05rem solid var(--md-default-fg-color--lightest);\n}\n.md-typeset a {\n color: var(--md-typeset-a-color);\n word-break: break-word;\n}\n.md-typeset a, .md-typeset a::before {\n transition: color 125ms;\n}\n.md-typeset a:focus, .md-typeset a:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset a.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n}\n.md-typeset code,\n.md-typeset pre,\n.md-typeset kbd {\n color: var(--md-code-fg-color);\n direction: ltr;\n}\n@media print {\n .md-typeset code,\n.md-typeset pre,\n.md-typeset kbd {\n white-space: pre-wrap;\n }\n}\n.md-typeset code {\n padding: 0 0.2941176471em;\n font-size: 0.85em;\n word-break: break-word;\n background-color: var(--md-code-bg-color);\n border-radius: 0.1rem;\n box-decoration-break: clone;\n}\n.md-typeset code:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset h1 code,\n.md-typeset h2 code,\n.md-typeset h3 code,\n.md-typeset h4 code,\n.md-typeset h5 code,\n.md-typeset h6 code {\n margin: initial;\n padding: initial;\n background-color: transparent;\n box-shadow: none;\n}\n.md-typeset a code {\n color: currentColor;\n}\n.md-typeset pre {\n position: relative;\n display: flow-root;\n line-height: 1.4;\n}\n.md-typeset pre > code {\n display: block;\n margin: 0;\n padding: 0.7720588235em 1.1764705882em;\n overflow: auto;\n word-break: normal;\n box-shadow: none;\n box-decoration-break: slice;\n touch-action: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n}\n.md-typeset pre > code:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-typeset pre > code::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n}\n.md-typeset pre > code::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset pre > code::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset > pre {\n margin: 1em -0.8rem;\n }\n .md-typeset > pre code {\n border-radius: 0;\n }\n}\n.md-typeset kbd {\n display: inline-block;\n padding: 0 0.6666666667em;\n color: var(--md-default-fg-color);\n font-size: 0.75em;\n vertical-align: text-top;\n word-break: break-word;\n background-color: var(--md-typeset-kbd-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.1rem 0 0.05rem var(--md-typeset-kbd-border-color), 0 0.1rem 0 var(--md-typeset-kbd-border-color), 0 -0.1rem 0.2rem var(--md-typeset-kbd-accent-color) inset;\n}\n.md-typeset mark {\n color: inherit;\n word-break: break-word;\n background-color: var(--md-typeset-mark-color);\n box-decoration-break: clone;\n}\n.md-typeset abbr {\n text-decoration: none;\n border-bottom: 0.05rem dotted var(--md-default-fg-color--light);\n cursor: help;\n}\n@media (hover: none) {\n .md-typeset abbr {\n position: relative;\n }\n .md-typeset abbr[title]:focus::after, .md-typeset abbr[title]:hover::after {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);\n position: absolute;\n left: 0;\n display: inline-block;\n width: auto;\n min-width: max-content;\n max-width: 80%;\n margin-top: 2em;\n padding: 0.2rem 0.3rem;\n color: var(--md-default-bg-color);\n font-size: 0.7rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n content: attr(title);\n }\n}\n.md-typeset small {\n opacity: 0.75;\n}\n.md-typeset sup,\n.md-typeset sub {\n margin-left: 0.078125em;\n}\n[dir=rtl] .md-typeset sup,\n[dir=rtl] .md-typeset sub {\n margin-right: 0.078125em;\n margin-left: initial;\n}\n.md-typeset blockquote {\n padding-left: 0.6rem;\n color: var(--md-default-fg-color--light);\n border-left: 0.2rem solid var(--md-default-fg-color--lighter);\n}\n[dir=rtl] .md-typeset blockquote {\n padding-right: 0.6rem;\n padding-left: initial;\n border-right: 0.2rem solid var(--md-default-fg-color--lighter);\n border-left: initial;\n}\n.md-typeset ul {\n list-style-type: disc;\n}\n.md-typeset ul,\n.md-typeset ol {\n display: flow-root;\n margin-left: 0.625em;\n padding: 0;\n}\n[dir=rtl] .md-typeset ul,\n[dir=rtl] .md-typeset ol {\n margin-right: 0.625em;\n margin-left: initial;\n}\n.md-typeset ul ol,\n.md-typeset ol ol {\n list-style-type: lower-alpha;\n}\n.md-typeset ul ol ol,\n.md-typeset ol ol ol {\n list-style-type: lower-roman;\n}\n.md-typeset ul li,\n.md-typeset ol li {\n margin-bottom: 0.5em;\n margin-left: 1.25em;\n}\n[dir=rtl] .md-typeset ul li,\n[dir=rtl] .md-typeset ol li {\n margin-right: 1.25em;\n margin-left: initial;\n}\n.md-typeset ul li p,\n.md-typeset ul li blockquote,\n.md-typeset ol li p,\n.md-typeset ol li blockquote {\n margin: 0.5em 0;\n}\n.md-typeset ul li:last-child,\n.md-typeset ol li:last-child {\n margin-bottom: 0;\n}\n.md-typeset ul li ul,\n.md-typeset ul li ol,\n.md-typeset ol li ul,\n.md-typeset ol li ol {\n margin: 0.5em 0 0.5em 0.625em;\n}\n[dir=rtl] .md-typeset ul li ul,\n[dir=rtl] .md-typeset ul li ol,\n[dir=rtl] .md-typeset ol li ul,\n[dir=rtl] .md-typeset ol li ol {\n margin-right: 0.625em;\n margin-left: initial;\n}\n.md-typeset dd {\n margin: 1em 0 1.5em 1.875em;\n}\n[dir=rtl] .md-typeset dd {\n margin-right: 1.875em;\n margin-left: initial;\n}\n.md-typeset img,\n.md-typeset svg {\n max-width: 100%;\n height: auto;\n}\n.md-typeset img[align=left],\n.md-typeset svg[align=left] {\n margin: 1em;\n margin-left: 0;\n}\n.md-typeset img[align=right],\n.md-typeset svg[align=right] {\n margin: 1em;\n margin-right: 0;\n}\n.md-typeset img[align]:only-child,\n.md-typeset svg[align]:only-child {\n margin-top: 0;\n}\n.md-typeset figure {\n display: flow-root;\n width: fit-content;\n max-width: 100%;\n margin: 0 auto;\n text-align: center;\n}\n.md-typeset figure img {\n display: block;\n}\n.md-typeset figcaption {\n max-width: 24rem;\n margin: 1em auto 2em;\n font-style: italic;\n}\n.md-typeset iframe {\n max-width: 100%;\n}\n.md-typeset table:not([class]) {\n display: inline-block;\n max-width: 100%;\n overflow: auto;\n font-size: 0.64rem;\n background-color: var(--md-default-bg-color);\n border: 0.05rem solid var(--md-typeset-table-color);\n border-radius: 0.1rem;\n touch-action: auto;\n}\n@media print {\n .md-typeset table:not([class]) {\n display: table;\n }\n}\n.md-typeset table:not([class]) + * {\n margin-top: 1.5em;\n}\n.md-typeset table:not([class]) th > *:first-child,\n.md-typeset table:not([class]) td > *:first-child {\n margin-top: 0;\n}\n.md-typeset table:not([class]) th > *:last-child,\n.md-typeset table:not([class]) td > *:last-child {\n margin-bottom: 0;\n}\n.md-typeset table:not([class]) th:not([align]),\n.md-typeset table:not([class]) td:not([align]) {\n text-align: left;\n}\n[dir=rtl] .md-typeset table:not([class]) th:not([align]),\n[dir=rtl] .md-typeset table:not([class]) td:not([align]) {\n text-align: right;\n}\n.md-typeset table:not([class]) th {\n min-width: 5rem;\n padding: 0.9375em 1.25em;\n font-weight: 700;\n vertical-align: top;\n}\n.md-typeset table:not([class]) th a {\n color: inherit;\n}\n.md-typeset table:not([class]) td {\n padding: 0.9375em 1.25em;\n vertical-align: top;\n border-top: 0.05rem solid var(--md-typeset-table-color);\n}\n.md-typeset table:not([class]) tbody tr {\n transition: background-color 125ms;\n}\n.md-typeset table:not([class]) tbody tr:hover {\n background-color: rgba(0, 0, 0, 0.035);\n box-shadow: 0 0.05rem 0 var(--md-default-bg-color) inset;\n}\n.md-typeset table:not([class]) a {\n word-break: normal;\n}\n.md-typeset table th[role=columnheader] {\n cursor: pointer;\n}\n.md-typeset table th[role=columnheader]::after {\n display: inline-block;\n width: 1.2em;\n height: 1.2em;\n margin-left: 0.5em;\n vertical-align: text-bottom;\n mask-image: var(--md-typeset-table-sort-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transition: background-color 125ms;\n content: \"\";\n}\n.md-typeset table th[role=columnheader]:hover::after {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset table th[role=columnheader][aria-sort=ascending]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--asc);\n}\n.md-typeset table th[role=columnheader][aria-sort=descending]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--desc);\n}\n.md-typeset__scrollwrap {\n margin: 1em -0.8rem;\n overflow-x: auto;\n touch-action: auto;\n}\n.md-typeset__table {\n display: inline-block;\n margin-bottom: 0.5em;\n padding: 0 0.8rem;\n}\n@media print {\n .md-typeset__table {\n display: block;\n }\n}\nhtml .md-typeset__table table {\n display: table;\n width: 100%;\n margin: 0;\n overflow: hidden;\n}\n\nhtml {\n height: 100%;\n overflow-x: hidden;\n font-size: 125%;\n}\n@media screen and (min-width: 100em) {\n html {\n font-size: 137.5%;\n }\n}\n@media screen and (min-width: 125em) {\n html {\n font-size: 150%;\n }\n}\n\nbody {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100%;\n font-size: 0.5rem;\n background-color: var(--md-default-bg-color);\n}\n@media print {\n body {\n display: block;\n }\n}\n@media screen and (max-width: 59.9375em) {\n body[data-md-state=lock] {\n position: fixed;\n }\n}\n\n.md-grid {\n max-width: 61rem;\n margin-right: auto;\n margin-left: auto;\n}\n\n.md-container {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n}\n@media print {\n .md-container {\n display: block;\n }\n}\n\n.md-main {\n flex-grow: 1;\n}\n.md-main__inner {\n display: flex;\n height: 100%;\n margin-top: 1.5rem;\n}\n\n.md-ellipsis {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.md-toggle {\n display: none;\n}\n\n.md-option {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n}\n.md-option:checked + label:not([hidden]) {\n display: block;\n}\n.md-option.focus-visible + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n}\n\n.md-skip {\n position: fixed;\n z-index: -1;\n margin: 0.5rem;\n padding: 0.3rem 0.5rem;\n color: var(--md-default-bg-color);\n font-size: 0.64rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n outline-color: var(--md-accent-fg-color);\n transform: translateY(0.4rem);\n opacity: 0;\n}\n.md-skip:focus {\n z-index: 10;\n transform: translateY(0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), opacity 175ms 75ms;\n}\n\n@page {\n margin: 25mm;\n}\n.md-announce {\n overflow: auto;\n background-color: var(--md-footer-bg-color);\n}\n@media print {\n .md-announce {\n display: none;\n }\n}\n.md-announce__inner {\n margin: 0.6rem auto;\n padding: 0 0.8rem;\n color: var(--md-footer-fg-color);\n font-size: 0.7rem;\n}\n\n:root {\n --md-clipboard-icon: svg-load(\"material/content-copy.svg\");\n}\n\n.md-clipboard {\n position: absolute;\n top: 0.5em;\n right: 0.5em;\n z-index: 1;\n width: 1.5em;\n height: 1.5em;\n color: var(--md-default-fg-color--lightest);\n border-radius: 0.1rem;\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.1rem;\n cursor: pointer;\n transition: color 250ms;\n}\n@media print {\n .md-clipboard {\n display: none;\n }\n}\n.md-clipboard:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n:hover > .md-clipboard {\n color: var(--md-default-fg-color--light);\n}\n.md-clipboard:focus, .md-clipboard:hover {\n color: var(--md-accent-fg-color);\n}\n.md-clipboard::after {\n display: block;\n width: 1.125em;\n height: 1.125em;\n margin: 0 auto;\n background-color: currentColor;\n mask-image: var(--md-clipboard-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n.md-clipboard--inline {\n cursor: pointer;\n}\n.md-clipboard--inline code {\n transition: color 250ms, background-color 250ms;\n}\n.md-clipboard--inline:focus code, .md-clipboard--inline:hover code {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n}\n\n.md-content {\n flex-grow: 1;\n overflow: hidden;\n scroll-padding-top: 51.2rem;\n}\n.md-content__inner {\n margin: 0 0.8rem 1.2rem;\n padding-top: 0.6rem;\n}\n@media screen and (min-width: 76.25em) {\n .md-sidebar--primary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-left: 1.2rem;\n }\n [dir=rtl] .md-sidebar--primary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-right: 1.2rem;\n margin-left: 0.8rem;\n }\n .md-sidebar--secondary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-right: 1.2rem;\n }\n [dir=rtl] .md-sidebar--secondary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-right: 0.8rem;\n margin-left: 1.2rem;\n }\n}\n.md-content__inner::before {\n display: block;\n height: 0.4rem;\n content: \"\";\n}\n.md-content__inner > :last-child {\n margin-bottom: 0;\n}\n.md-content__button {\n float: right;\n margin: 0.4rem 0;\n margin-left: 0.4rem;\n padding: 0;\n}\n@media print {\n .md-content__button {\n display: none;\n }\n}\n[dir=rtl] .md-content__button {\n float: left;\n margin-right: 0.4rem;\n margin-left: initial;\n}\n[dir=rtl] .md-content__button svg {\n transform: scaleX(-1);\n}\n.md-typeset .md-content__button {\n color: var(--md-default-fg-color--lighter);\n}\n.md-content__button svg {\n display: inline;\n vertical-align: top;\n}\n\n.md-dialog {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);\n position: fixed;\n right: 0.8rem;\n bottom: 0.8rem;\n left: initial;\n z-index: 3;\n min-width: 11.1rem;\n padding: 0.4rem 0.6rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n transform: translateY(100%);\n opacity: 0;\n transition: transform 0ms 400ms, opacity 400ms;\n pointer-events: none;\n}\n@media print {\n .md-dialog {\n display: none;\n }\n}\n[dir=rtl] .md-dialog {\n right: initial;\n left: 0.8rem;\n}\n.md-dialog[data-md-state=open] {\n transform: translateY(0);\n opacity: 1;\n transition: transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1), opacity 400ms;\n pointer-events: initial;\n}\n.md-dialog__inner {\n color: var(--md-default-bg-color);\n font-size: 0.7rem;\n}\n\n.md-typeset .md-button {\n display: inline-block;\n padding: 0.625em 2em;\n color: var(--md-primary-fg-color);\n font-weight: 700;\n border: 0.1rem solid currentColor;\n border-radius: 0.1rem;\n cursor: pointer;\n transition: color 125ms, background-color 125ms, border-color 125ms;\n}\n.md-typeset .md-button--primary {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n border-color: var(--md-primary-fg-color);\n}\n.md-typeset .md-button:focus, .md-typeset .md-button:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n}\n.md-typeset .md-input {\n height: 1.8rem;\n padding: 0 0.6rem;\n font-size: 0.8rem;\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.1);\n transition: box-shadow 250ms;\n}\n.md-typeset .md-input:focus, .md-typeset .md-input:hover {\n box-shadow: 0 0.4rem 1rem rgba(0, 0, 0, 0.15), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.15);\n}\n.md-typeset .md-input--stretch {\n width: 100%;\n}\n\n.md-header {\n position: sticky;\n top: 0;\n right: 0;\n left: 0;\n z-index: 3;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0), 0 0.2rem 0.4rem rgba(0, 0, 0, 0);\n}\n@media print {\n .md-header {\n display: none;\n }\n}\n.md-header[data-md-state=shadow] {\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2);\n transition: transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), box-shadow 250ms;\n}\n.md-header[data-md-state=hidden] {\n transform: translateY(-100%);\n transition: transform 250ms cubic-bezier(0.8, 0, 0.6, 1), box-shadow 250ms;\n}\n.md-header__inner {\n display: flex;\n align-items: center;\n padding: 0 0.2rem;\n}\n.md-header__button {\n position: relative;\n z-index: 1;\n margin: 0.2rem;\n padding: 0.4rem;\n color: currentColor;\n vertical-align: middle;\n outline-color: var(--md-accent-fg-color);\n cursor: pointer;\n transition: opacity 250ms;\n}\n.md-header__button:hover {\n opacity: 0.7;\n}\n.md-header__button:not([hidden]) {\n display: inline-block;\n}\n.md-header__button:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-header__button.md-logo {\n margin: 0.2rem;\n padding: 0.4rem;\n}\n@media screen and (max-width: 76.1875em) {\n .md-header__button.md-logo {\n display: none;\n }\n}\n.md-header__button.md-logo img,\n.md-header__button.md-logo svg {\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n fill: currentColor;\n}\n@media screen and (min-width: 60em) {\n .md-header__button[for=__search] {\n display: none;\n }\n}\n.no-js .md-header__button[for=__search] {\n display: none;\n}\n[dir=rtl] .md-header__button[for=__search] svg {\n transform: scaleX(-1);\n}\n@media screen and (min-width: 76.25em) {\n .md-header__button[for=__drawer] {\n display: none;\n }\n}\n.md-header__topic {\n position: absolute;\n display: flex;\n max-width: 100%;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n}\n.md-header__topic + .md-header__topic {\n z-index: -1;\n transform: translateX(1.25rem);\n opacity: 0;\n transition: transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), opacity 150ms;\n pointer-events: none;\n}\n[dir=rtl] .md-header__topic + .md-header__topic {\n transform: translateX(-1.25rem);\n}\n.md-header__title {\n flex-grow: 1;\n height: 2.4rem;\n margin-right: 0.4rem;\n margin-left: 1rem;\n font-size: 0.9rem;\n line-height: 2.4rem;\n}\n.md-header__title[data-md-state=active] .md-header__topic {\n z-index: -1;\n transform: translateX(-1.25rem);\n opacity: 0;\n transition: transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), opacity 150ms;\n pointer-events: none;\n}\n[dir=rtl] .md-header__title[data-md-state=active] .md-header__topic {\n transform: translateX(1.25rem);\n}\n.md-header__title[data-md-state=active] .md-header__topic + .md-header__topic {\n z-index: 0;\n transform: translateX(0);\n opacity: 1;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n pointer-events: initial;\n}\n.md-header__title > .md-header__ellipsis {\n position: relative;\n width: 100%;\n height: 100%;\n}\n.md-header__option {\n display: flex;\n flex-shrink: 0;\n max-width: 100%;\n white-space: nowrap;\n transition: max-width 0ms 250ms, opacity 250ms 250ms;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-header__option {\n max-width: 0;\n opacity: 0;\n transition: max-width 0ms, opacity 0ms;\n}\n.md-header__source {\n display: none;\n}\n@media screen and (min-width: 60em) {\n .md-header__source {\n display: block;\n width: 11.7rem;\n max-width: 11.7rem;\n margin-left: 1rem;\n }\n [dir=rtl] .md-header__source {\n margin-right: 1rem;\n margin-left: initial;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-header__source {\n margin-left: 1.4rem;\n }\n [dir=rtl] .md-header__source {\n margin-right: 1.4rem;\n }\n}\n\n.md-footer {\n color: var(--md-footer-fg-color);\n background-color: var(--md-footer-bg-color);\n}\n@media print {\n .md-footer {\n display: none;\n }\n}\n.md-footer__inner {\n padding: 0.2rem;\n overflow: auto;\n}\n.md-footer__link {\n display: flex;\n padding-top: 1.4rem;\n padding-bottom: 0.4rem;\n outline-color: var(--md-accent-fg-color);\n transition: opacity 250ms;\n}\n@media screen and (min-width: 45em) {\n .md-footer__link {\n width: 50%;\n }\n}\n.md-footer__link:focus, .md-footer__link:hover {\n opacity: 0.7;\n}\n.md-footer__link--prev {\n float: left;\n}\n@media screen and (max-width: 44.9375em) {\n .md-footer__link--prev {\n width: 25%;\n }\n .md-footer__link--prev .md-footer__title {\n display: none;\n }\n}\n[dir=rtl] .md-footer__link--prev {\n float: right;\n}\n[dir=rtl] .md-footer__link--prev svg {\n transform: scaleX(-1);\n}\n.md-footer__link--next {\n float: right;\n text-align: right;\n}\n@media screen and (max-width: 44.9375em) {\n .md-footer__link--next {\n width: 75%;\n }\n}\n[dir=rtl] .md-footer__link--next {\n float: left;\n text-align: left;\n}\n[dir=rtl] .md-footer__link--next svg {\n transform: scaleX(-1);\n}\n.md-footer__title {\n position: relative;\n flex-grow: 1;\n max-width: calc(100% - 2.4rem);\n padding: 0 1rem;\n font-size: 0.9rem;\n line-height: 2.4rem;\n}\n.md-footer__button {\n margin: 0.2rem;\n padding: 0.4rem;\n}\n.md-footer__direction {\n position: absolute;\n right: 0;\n left: 0;\n margin-top: -1rem;\n padding: 0 1rem;\n font-size: 0.64rem;\n opacity: 0.7;\n}\n\n.md-footer-meta {\n background-color: var(--md-footer-bg-color--dark);\n}\n.md-footer-meta__inner {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n padding: 0.2rem;\n}\nhtml .md-footer-meta.md-typeset a {\n color: var(--md-footer-fg-color--light);\n}\nhtml .md-footer-meta.md-typeset a:focus, html .md-footer-meta.md-typeset a:hover {\n color: var(--md-footer-fg-color);\n}\n\n.md-footer-copyright {\n width: 100%;\n margin: auto 0.6rem;\n padding: 0.4rem 0;\n color: var(--md-footer-fg-color--lighter);\n font-size: 0.64rem;\n}\n@media screen and (min-width: 45em) {\n .md-footer-copyright {\n width: auto;\n }\n}\n.md-footer-copyright__highlight {\n color: var(--md-footer-fg-color--light);\n}\n\n.md-footer-social {\n margin: 0 0.4rem;\n padding: 0.2rem 0 0.6rem;\n}\n@media screen and (min-width: 45em) {\n .md-footer-social {\n padding: 0.6rem 0;\n }\n}\n.md-footer-social__link {\n display: inline-block;\n width: 1.6rem;\n height: 1.6rem;\n text-align: center;\n}\n.md-footer-social__link::before {\n line-height: 1.9;\n}\n.md-footer-social__link svg {\n max-height: 0.8rem;\n vertical-align: -25%;\n fill: currentColor;\n}\n\n:root {\n --md-nav-icon--prev: svg-load(\"material/arrow-left.svg\");\n --md-nav-icon--next: svg-load(\"material/chevron-right.svg\");\n --md-toc-icon: svg-load(\"material/table-of-contents.svg\");\n}\n\n.md-nav {\n font-size: 0.7rem;\n line-height: 1.3;\n}\n.md-nav__title {\n display: block;\n padding: 0 0.6rem;\n overflow: hidden;\n font-weight: 700;\n text-overflow: ellipsis;\n}\n.md-nav__title .md-nav__button {\n display: none;\n}\n.md-nav__title .md-nav__button img {\n width: auto;\n height: 100%;\n}\n.md-nav__title .md-nav__button.md-logo img,\n.md-nav__title .md-nav__button.md-logo svg {\n display: block;\n width: 2.4rem;\n height: 2.4rem;\n fill: currentColor;\n}\n.md-nav__list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.md-nav__item {\n padding: 0 0.6rem;\n}\n.md-nav__item .md-nav__item {\n padding-right: 0;\n}\n[dir=rtl] .md-nav__item .md-nav__item {\n padding-right: 0.6rem;\n padding-left: 0;\n}\n.md-nav__link {\n display: block;\n margin-top: 0.625em;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n transition: color 125ms;\n scroll-snap-align: start;\n}\n.md-nav__link[data-md-state=blur] {\n color: var(--md-default-fg-color--light);\n}\n.md-nav__item .md-nav__link--active {\n color: var(--md-typeset-a-color);\n}\n.md-nav__item--nested > .md-nav__link {\n color: inherit;\n}\n.md-nav__link:focus, .md-nav__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-nav__link.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n}\n.md-nav--primary .md-nav__link[for=__toc] {\n display: none;\n}\n.md-nav--primary .md-nav__link[for=__toc] .md-icon::after {\n display: block;\n width: 100%;\n height: 100%;\n mask-image: var(--md-toc-icon);\n background-color: currentColor;\n}\n.md-nav--primary .md-nav__link[for=__toc] ~ .md-nav {\n display: none;\n}\n.md-nav__source {\n display: none;\n}\n@media screen and (max-width: 76.1875em) {\n .md-nav--primary, .md-nav--primary .md-nav {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--md-default-bg-color);\n }\n .md-nav--primary .md-nav__title,\n.md-nav--primary .md-nav__item {\n font-size: 0.8rem;\n line-height: 1.5;\n }\n .md-nav--primary .md-nav__title {\n position: relative;\n height: 5.6rem;\n padding: 3rem 0.8rem 0.2rem;\n color: var(--md-default-fg-color--light);\n font-weight: 400;\n line-height: 2.4rem;\n white-space: nowrap;\n background-color: var(--md-default-fg-color--lightest);\n cursor: pointer;\n }\n .md-nav--primary .md-nav__title .md-nav__icon {\n position: absolute;\n top: 0.4rem;\n left: 0.4rem;\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n margin: 0.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon {\n right: 0.4rem;\n left: initial;\n }\n .md-nav--primary .md-nav__title .md-nav__icon::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--prev);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n .md-nav--primary .md-nav__title ~ .md-nav__list {\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0.05rem 0 var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: y mandatory;\n touch-action: pan-y;\n }\n .md-nav--primary .md-nav__title ~ .md-nav__list > :first-child {\n border-top: 0;\n }\n .md-nav--primary .md-nav__title[for=__drawer] {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n }\n .md-nav--primary .md-nav__title .md-logo {\n position: absolute;\n top: 0.2rem;\n left: 0.2rem;\n display: block;\n margin: 0.2rem;\n padding: 0.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__title .md-logo {\n right: 0.2rem;\n left: initial;\n }\n .md-nav--primary .md-nav__list {\n flex: 1;\n }\n .md-nav--primary .md-nav__item {\n padding: 0;\n border-top: 0.05rem solid var(--md-default-fg-color--lightest);\n }\n .md-nav--primary .md-nav__item--nested > .md-nav__link {\n padding-right: 2.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__item--nested > .md-nav__link {\n padding-right: 0.8rem;\n padding-left: 2.4rem;\n }\n .md-nav--primary .md-nav__item--active > .md-nav__link {\n color: var(--md-typeset-a-color);\n }\n .md-nav--primary .md-nav__item--active > .md-nav__link:focus, .md-nav--primary .md-nav__item--active > .md-nav__link:hover {\n color: var(--md-accent-fg-color);\n }\n .md-nav--primary .md-nav__link {\n position: relative;\n margin-top: 0;\n padding: 0.6rem 0.8rem;\n }\n .md-nav--primary .md-nav__link .md-nav__icon {\n position: absolute;\n top: 50%;\n right: 0.6rem;\n width: 1.2rem;\n height: 1.2rem;\n margin-top: -0.6rem;\n color: inherit;\n font-size: 1.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon {\n right: initial;\n left: 0.6rem;\n }\n .md-nav--primary .md-nav__link .md-nav__icon::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n [dir=rtl] .md-nav--primary .md-nav__icon::after {\n transform: scale(-1);\n }\n .md-nav--primary .md-nav--secondary .md-nav__link {\n position: static;\n }\n .md-nav--primary .md-nav--secondary .md-nav {\n position: static;\n background-color: transparent;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav__link {\n padding-left: 1.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link {\n padding-right: 1.4rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link {\n padding-left: 2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link {\n padding-right: 2rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: 2.6rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link {\n padding-right: 2.6rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: 3.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link {\n padding-right: 3.2rem;\n padding-left: initial;\n }\n .md-nav--secondary {\n background-color: transparent;\n }\n .md-nav__toggle ~ .md-nav {\n display: flex;\n transform: translateX(100%);\n opacity: 0;\n transition: transform 250ms cubic-bezier(0.8, 0, 0.6, 1), opacity 125ms 50ms;\n }\n [dir=rtl] .md-nav__toggle ~ .md-nav {\n transform: translateX(-100%);\n }\n .md-nav__toggle:checked ~ .md-nav {\n transform: translateX(0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), opacity 125ms 125ms;\n }\n .md-nav__toggle:checked ~ .md-nav > .md-nav__list {\n backface-visibility: hidden;\n }\n}\n@media screen and (max-width: 59.9375em) {\n .md-nav--primary .md-nav__link[for=__toc] {\n display: block;\n padding-right: 2.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__link[for=__toc] {\n padding-right: 0.8rem;\n padding-left: 2.4rem;\n }\n .md-nav--primary .md-nav__link[for=__toc] .md-icon::after {\n content: \"\";\n }\n .md-nav--primary .md-nav__link[for=__toc] + .md-nav__link {\n display: none;\n }\n .md-nav--primary .md-nav__link[for=__toc] ~ .md-nav {\n display: flex;\n }\n .md-nav__source {\n display: block;\n padding: 0 0.2rem;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color--dark);\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-nav--integrated .md-nav__link[for=__toc] {\n display: block;\n padding-right: 2.4rem;\n scroll-snap-align: initial;\n }\n [dir=rtl] .md-nav--integrated .md-nav__link[for=__toc] {\n padding-right: 0.8rem;\n padding-left: 2.4rem;\n }\n .md-nav--integrated .md-nav__link[for=__toc] .md-icon::after {\n content: \"\";\n }\n .md-nav--integrated .md-nav__link[for=__toc] + .md-nav__link {\n display: none;\n }\n .md-nav--integrated .md-nav__link[for=__toc] ~ .md-nav {\n display: flex;\n }\n}\n@media screen and (min-width: 60em) {\n .md-nav--secondary .md-nav__title[for=__toc] {\n scroll-snap-align: start;\n }\n .md-nav--secondary .md-nav__title .md-nav__icon {\n display: none;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-nav {\n transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1);\n }\n .md-nav--primary .md-nav__title[for=__drawer] {\n scroll-snap-align: start;\n }\n .md-nav--primary .md-nav__title .md-nav__icon {\n display: none;\n }\n .md-nav__toggle ~ .md-nav {\n display: none;\n }\n .md-nav__toggle:checked ~ .md-nav, .md-nav__toggle:indeterminate ~ .md-nav {\n display: block;\n }\n .md-nav__item--nested > .md-nav > .md-nav__title {\n display: none;\n }\n .md-nav__item--section {\n display: block;\n margin: 1.25em 0;\n }\n .md-nav__item--section:last-child {\n margin-bottom: 0;\n }\n .md-nav__item--section > .md-nav__link {\n display: none;\n }\n .md-nav__item--section > .md-nav {\n display: block;\n }\n .md-nav__item--section > .md-nav > .md-nav__title {\n display: block;\n padding: 0;\n pointer-events: none;\n scroll-snap-align: start;\n }\n .md-nav__item--section > .md-nav > .md-nav__list > .md-nav__item {\n padding: 0;\n }\n .md-nav__icon {\n float: right;\n width: 0.9rem;\n height: 0.9rem;\n transition: transform 250ms;\n }\n [dir=rtl] .md-nav__icon {\n float: left;\n transform: rotate(180deg);\n }\n .md-nav__icon::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n vertical-align: -0.1rem;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link .md-nav__icon, .md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link .md-nav__icon {\n transform: rotate(90deg);\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--nested,\n.md-nav--lifted > .md-nav__title {\n display: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item {\n display: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active {\n display: block;\n padding: 0;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link {\n display: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav > .md-nav__title {\n display: block;\n padding: 0 0.6rem;\n pointer-events: none;\n scroll-snap-align: start;\n }\n .md-nav--lifted .md-nav[data-md-level=\"1\"] {\n display: block;\n }\n .md-nav--lifted .md-nav[data-md-level=\"1\"] > .md-nav__list > .md-nav__item {\n padding-right: 0.6rem;\n }\n .md-nav--integrated .md-nav__link[for=__toc] ~ .md-nav {\n display: block;\n margin-bottom: 1.25em;\n border-left: 0.05rem solid var(--md-primary-fg-color);\n }\n .md-nav--integrated .md-nav__link[for=__toc] ~ .md-nav > .md-nav__title {\n display: none;\n }\n}\n\n:root {\n --md-search-result-icon: svg-load(\"material/file-search-outline.svg\");\n}\n\n.md-search {\n position: relative;\n}\n@media screen and (min-width: 60em) {\n .md-search {\n padding: 0.2rem 0;\n }\n}\n.no-js .md-search {\n display: none;\n}\n.md-search__overlay {\n z-index: 1;\n opacity: 0;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__overlay {\n position: absolute;\n top: -1rem;\n left: -2.2rem;\n width: 2rem;\n height: 2rem;\n overflow: hidden;\n background-color: var(--md-default-bg-color);\n border-radius: 1rem;\n transform-origin: center;\n transition: transform 300ms 100ms, opacity 200ms 200ms;\n pointer-events: none;\n }\n [dir=rtl] .md-search__overlay {\n right: -2.2rem;\n left: initial;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n opacity: 1;\n transition: transform 400ms, opacity 100ms;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n background-color: rgba(0, 0, 0, 0.54);\n cursor: pointer;\n transition: width 0ms 250ms, height 0ms 250ms, opacity 250ms;\n }\n [dir=rtl] .md-search__overlay {\n right: 0;\n left: initial;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n width: 100%;\n height: 200vh;\n opacity: 1;\n transition: width 0ms, height 0ms, opacity 250ms;\n }\n}\n@media screen and (max-width: 29.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(45);\n }\n}\n@media screen and (min-width: 30em) and (max-width: 44.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(60);\n }\n}\n@media screen and (min-width: 45em) and (max-width: 59.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(75);\n }\n}\n.md-search__inner {\n backface-visibility: hidden;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__inner {\n position: fixed;\n top: 0;\n left: 100%;\n z-index: 2;\n width: 100%;\n height: 100%;\n transform: translateX(5%);\n opacity: 0;\n transition: right 0ms 300ms, left 0ms 300ms, transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1), opacity 150ms 150ms;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n left: 0;\n transform: translateX(0);\n opacity: 1;\n transition: right 0ms 0ms, left 0ms 0ms, transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms 150ms;\n }\n [dir=rtl] [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n right: 0;\n left: initial;\n }\n html [dir=rtl] .md-search__inner {\n right: 100%;\n left: initial;\n transform: translateX(-5%);\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__inner {\n position: relative;\n float: right;\n width: 11.7rem;\n padding: 0.1rem 0;\n transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1);\n }\n [dir=rtl] .md-search__inner {\n float: left;\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n width: 23.4rem;\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n width: 34.4rem;\n }\n}\n.md-search__form {\n position: relative;\n z-index: 2;\n height: 2.4rem;\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0 0.6rem transparent;\n transition: color 250ms, background-color 250ms;\n}\n@media screen and (min-width: 60em) {\n .md-search__form {\n height: 1.8rem;\n background-color: rgba(0, 0, 0, 0.26);\n border-radius: 0.1rem;\n }\n .md-search__form:hover {\n background-color: rgba(255, 255, 255, 0.12);\n }\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__form {\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem 0.1rem 0 0;\n box-shadow: 0 0 0.6rem rgba(0, 0, 0, 0.07);\n}\n.md-search__input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: 100%;\n padding: 0 2.2rem 0 3.6rem;\n font-size: 0.9rem;\n text-overflow: ellipsis;\n background: transparent;\n}\n[dir=rtl] .md-search__input {\n padding: 0 3.6rem 0 2.2rem;\n}\n.md-search__input::placeholder {\n transition: color 250ms;\n}\n.md-search__input ~ .md-search__icon, .md-search__input::placeholder {\n color: var(--md-default-fg-color--light);\n}\n.md-search__input::-ms-clear {\n display: none;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__input {\n width: 100%;\n height: 2.4rem;\n font-size: 0.9rem;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__input {\n padding-left: 2.2rem;\n color: inherit;\n font-size: 0.8rem;\n }\n [dir=rtl] .md-search__input {\n padding-right: 2.2rem;\n }\n .md-search__input::placeholder {\n color: var(--md-primary-bg-color--light);\n }\n .md-search__input + .md-search__icon {\n color: var(--md-primary-bg-color);\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__input {\n text-overflow: clip;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__input + .md-search__icon, [data-md-toggle=search]:checked ~ .md-header .md-search__input::placeholder {\n color: var(--md-default-fg-color--light);\n }\n}\n.md-search__icon {\n display: inline-block;\n width: 1.2rem;\n height: 1.2rem;\n cursor: pointer;\n transition: color 250ms, opacity 250ms;\n}\n.md-search__icon:hover {\n opacity: 0.7;\n}\n.md-search__icon[for=__search] {\n position: absolute;\n top: 0.3rem;\n left: 0.5rem;\n z-index: 2;\n}\n[dir=rtl] .md-search__icon[for=__search] {\n right: 0.5rem;\n left: initial;\n}\n[dir=rtl] .md-search__icon[for=__search] svg {\n transform: scaleX(-1);\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__icon[for=__search] {\n top: 0.6rem;\n left: 0.8rem;\n }\n [dir=rtl] .md-search__icon[for=__search] {\n right: 0.8rem;\n left: initial;\n }\n .md-search__icon[for=__search] svg:first-child {\n display: none;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__icon[for=__search] {\n pointer-events: none;\n }\n .md-search__icon[for=__search] svg:last-child {\n display: none;\n }\n}\n.md-search__options {\n position: absolute;\n top: 0.3rem;\n right: 0.5rem;\n z-index: 2;\n pointer-events: none;\n}\n[dir=rtl] .md-search__options {\n right: initial;\n left: 0.5rem;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__options {\n top: 0.6rem;\n right: 0.8rem;\n }\n [dir=rtl] .md-search__options {\n right: initial;\n left: 0.8rem;\n }\n}\n.md-search__options > * {\n margin-left: 0.2rem;\n color: var(--md-default-fg-color--light);\n transform: scale(0.75);\n opacity: 0;\n transition: transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n}\n.md-search__options > *:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__input:valid ~ .md-search__options > * {\n transform: scale(1);\n opacity: 1;\n pointer-events: initial;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__input:valid ~ .md-search__options > *:hover {\n opacity: 0.7;\n}\n.md-search__suggest {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n padding: 0 2.2rem 0 3.6rem;\n color: var(--md-default-fg-color--lighter);\n font-size: 0.9rem;\n white-space: nowrap;\n opacity: 0;\n transition: opacity 50ms;\n}\n[dir=rtl] .md-search__suggest {\n padding: 0 3.6rem 0 2.2rem;\n}\n@media screen and (min-width: 60em) {\n .md-search__suggest {\n padding-left: 2.2rem;\n font-size: 0.8rem;\n }\n [dir=rtl] .md-search__suggest {\n padding-right: 2.2rem;\n }\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__suggest {\n opacity: 1;\n transition: opacity 300ms 100ms;\n}\n.md-search__output {\n position: absolute;\n z-index: 1;\n width: 100%;\n overflow: hidden;\n border-radius: 0 0 0.1rem 0.1rem;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__output {\n top: 2.4rem;\n bottom: 0;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__output {\n top: 1.9rem;\n opacity: 0;\n transition: opacity 400ms;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__output {\n box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.4);\n opacity: 1;\n }\n}\n.md-search__scrollwrap {\n height: 100%;\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n backface-visibility: hidden;\n touch-action: pan-y;\n}\n@media (max-resolution: 1dppx) {\n .md-search__scrollwrap {\n transform: translateZ(0);\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-search__scrollwrap {\n width: 23.4rem;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-search__scrollwrap {\n width: 34.4rem;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__scrollwrap {\n max-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__scrollwrap {\n max-height: 75vh;\n }\n .md-search__scrollwrap:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n .md-search__scrollwrap::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n }\n .md-search__scrollwrap::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n }\n .md-search__scrollwrap::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n }\n}\n\n.md-search-result {\n color: var(--md-default-fg-color);\n word-break: break-word;\n}\n.md-search-result__meta {\n padding: 0 0.8rem;\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n line-height: 1.8rem;\n background-color: var(--md-default-fg-color--lightest);\n scroll-snap-align: start;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__meta {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__meta {\n padding-right: 2.2rem;\n padding-left: initial;\n }\n}\n.md-search-result__list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.md-search-result__item {\n box-shadow: 0 -0.05rem 0 var(--md-default-fg-color--lightest);\n}\n.md-search-result__item:first-child {\n box-shadow: none;\n}\n.md-search-result__link {\n display: block;\n outline: none;\n transition: background-color 250ms;\n scroll-snap-align: start;\n}\n.md-search-result__link:focus, .md-search-result__link:hover {\n background-color: var(--md-accent-fg-color--transparent);\n}\n.md-search-result__link:last-child p:last-child {\n margin-bottom: 0.6rem;\n}\n.md-search-result__more summary {\n display: block;\n padding: 0.75em 0.8rem;\n color: var(--md-typeset-a-color);\n font-size: 0.64rem;\n outline: none;\n cursor: pointer;\n transition: color 250ms, background-color 250ms;\n scroll-snap-align: start;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__more summary {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__more summary {\n padding-right: 2.2rem;\n padding-left: 0.8rem;\n }\n}\n.md-search-result__more summary:focus, .md-search-result__more summary:hover {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n}\n.md-search-result__more summary::marker, .md-search-result__more summary::-webkit-details-marker {\n display: none;\n}\n.md-search-result__more summary ~ * > * {\n opacity: 0.65;\n}\n.md-search-result__article {\n position: relative;\n padding: 0 0.8rem;\n overflow: hidden;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__article {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__article {\n padding-right: 2.2rem;\n padding-left: 0.8rem;\n }\n}\n.md-search-result__article--document .md-search-result__title {\n margin: 0.55rem 0;\n font-weight: 400;\n font-size: 0.8rem;\n line-height: 1.4;\n}\n.md-search-result__icon {\n position: absolute;\n left: 0;\n width: 1.2rem;\n height: 1.2rem;\n margin: 0.5rem;\n color: var(--md-default-fg-color--light);\n}\n@media screen and (max-width: 59.9375em) {\n .md-search-result__icon {\n display: none;\n }\n}\n.md-search-result__icon::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-search-result-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-search-result__icon {\n right: 0;\n left: initial;\n}\n[dir=rtl] .md-search-result__icon::after {\n transform: scaleX(-1);\n}\n.md-search-result__title {\n margin: 0.5em 0;\n font-weight: 700;\n font-size: 0.64rem;\n line-height: 1.6;\n}\n.md-search-result__teaser {\n display: -webkit-box;\n max-height: 2rem;\n margin: 0.5em 0;\n overflow: hidden;\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n line-height: 1.6;\n text-overflow: ellipsis;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n}\n@media screen and (max-width: 44.9375em) {\n .md-search-result__teaser {\n max-height: 3rem;\n -webkit-line-clamp: 3;\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-search-result__teaser {\n max-height: 3rem;\n -webkit-line-clamp: 3;\n }\n}\n.md-search-result__teaser mark {\n text-decoration: underline;\n background-color: transparent;\n}\n.md-search-result__terms {\n margin: 0.5em 0;\n font-size: 0.64rem;\n font-style: italic;\n}\n.md-search-result mark {\n color: var(--md-accent-fg-color);\n background-color: transparent;\n}\n\n.md-select {\n position: relative;\n z-index: 1;\n}\n.md-select__inner {\n position: absolute;\n top: calc(100% - 0.2rem);\n left: 50%;\n max-height: 0;\n margin-top: 0.2rem;\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n transform: translate3d(-50%, 0.3rem, 0);\n opacity: 0;\n transition: transform 250ms 375ms, opacity 250ms 250ms, max-height 0ms 500ms;\n}\n.md-select:focus-within .md-select__inner, .md-select:hover .md-select__inner {\n max-height: 10rem;\n transform: translate3d(-50%, 0, 0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 250ms, max-height 0ms;\n}\n.md-select__inner::after {\n position: absolute;\n top: 0;\n left: 50%;\n width: 0;\n height: 0;\n margin-top: -0.2rem;\n margin-left: -0.2rem;\n border: 0.2rem solid transparent;\n border-top: 0;\n border-bottom-color: var(--md-default-bg-color);\n content: \"\";\n}\n.md-select__list {\n max-height: inherit;\n margin: 0;\n padding: 0;\n overflow: auto;\n font-size: 0.8rem;\n list-style-type: none;\n border-radius: 0.1rem;\n}\n.md-select__item {\n line-height: 1.8rem;\n}\n.md-select__link {\n display: block;\n width: 100%;\n padding-right: 1.2rem;\n padding-left: 0.6rem;\n outline: none;\n cursor: pointer;\n transition: background-color 250ms, color 250ms;\n scroll-snap-align: start;\n}\n[dir=rtl] .md-select__link {\n padding-right: 0.6rem;\n padding-left: 1.2rem;\n}\n.md-select__link:focus, .md-select__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-select__link:focus {\n background-color: var(--md-default-fg-color--lightest);\n}\n\n.md-sidebar {\n position: sticky;\n top: 2.4rem;\n flex-shrink: 0;\n align-self: flex-start;\n width: 12.1rem;\n padding: 1.2rem 0;\n}\n@media print {\n .md-sidebar {\n display: none;\n }\n}\n@media screen and (max-width: 76.1875em) {\n .md-sidebar--primary {\n position: fixed;\n top: 0;\n left: -12.1rem;\n z-index: 4;\n display: block;\n width: 12.1rem;\n height: 100%;\n background-color: var(--md-default-bg-color);\n transform: translateX(0);\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 250ms;\n }\n [dir=rtl] .md-sidebar--primary {\n right: -12.1rem;\n left: initial;\n }\n [data-md-toggle=drawer]:checked ~ .md-container .md-sidebar--primary {\n box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.4);\n transform: translateX(12.1rem);\n }\n [dir=rtl] [data-md-toggle=drawer]:checked ~ .md-container .md-sidebar--primary {\n transform: translateX(-12.1rem);\n }\n .md-sidebar--primary .md-sidebar__scrollwrap {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n margin: 0;\n scroll-snap-type: none;\n overflow: hidden;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-sidebar {\n height: 0;\n }\n .no-js .md-sidebar {\n height: auto;\n }\n}\n.md-sidebar--secondary {\n display: none;\n order: 2;\n}\n@media screen and (min-width: 60em) {\n .md-sidebar--secondary {\n height: 0;\n }\n .no-js .md-sidebar--secondary {\n height: auto;\n }\n .md-sidebar--secondary:not([hidden]) {\n display: block;\n }\n .md-sidebar--secondary .md-sidebar__scrollwrap {\n touch-action: pan-y;\n }\n}\n.md-sidebar__scrollwrap {\n margin: 0 0.2rem;\n overflow-y: auto;\n backface-visibility: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n}\n.md-sidebar__scrollwrap:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n}\n\n@media screen and (max-width: 76.1875em) {\n .md-overlay {\n position: fixed;\n top: 0;\n z-index: 4;\n width: 0;\n height: 0;\n background-color: rgba(0, 0, 0, 0.54);\n opacity: 0;\n transition: width 0ms 250ms, height 0ms 250ms, opacity 250ms;\n }\n [data-md-toggle=drawer]:checked ~ .md-overlay {\n width: 100%;\n height: 100%;\n opacity: 1;\n transition: width 0ms, height 0ms, opacity 250ms;\n }\n}\n@keyframes facts {\n 0% {\n height: 0;\n }\n 100% {\n height: 0.65rem;\n }\n}\n@keyframes fact {\n 0% {\n transform: translateY(100%);\n opacity: 0;\n }\n 50% {\n opacity: 0;\n }\n 100% {\n transform: translateY(0%);\n opacity: 1;\n }\n}\n:root {\n --md-source-forks-icon: svg-load(\"octicons/repo-forked-16.svg\");\n --md-source-repositories-icon: svg-load(\"octicons/repo-16.svg\");\n --md-source-stars-icon: svg-load(\"octicons/star-16.svg\");\n --md-source-version-icon: svg-load(\"octicons/tag-16.svg\");\n}\n\n.md-source {\n display: block;\n font-size: 0.65rem;\n line-height: 1.2;\n white-space: nowrap;\n outline-color: var(--md-accent-fg-color);\n backface-visibility: hidden;\n transition: opacity 250ms;\n}\n.md-source:hover {\n opacity: 0.7;\n}\n.md-source__icon {\n display: inline-block;\n width: 2rem;\n height: 2.4rem;\n vertical-align: middle;\n}\n.md-source__icon svg {\n margin-top: 0.6rem;\n margin-left: 0.6rem;\n}\n[dir=rtl] .md-source__icon svg {\n margin-right: 0.6rem;\n margin-left: initial;\n}\n.md-source__icon + .md-source__repository {\n margin-left: -2rem;\n padding-left: 2rem;\n}\n[dir=rtl] .md-source__icon + .md-source__repository {\n margin-right: -2rem;\n margin-left: initial;\n padding-right: 2rem;\n padding-left: initial;\n}\n.md-source__repository {\n display: inline-block;\n max-width: calc(100% - 1.2rem);\n margin-left: 0.6rem;\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n}\n.md-source__facts {\n margin: 0.1rem 0 0;\n padding: 0;\n overflow: hidden;\n font-size: 0.55rem;\n list-style-type: none;\n opacity: 0.75;\n}\n[data-md-state=done] .md-source__facts {\n animation: facts 250ms ease-in;\n}\n.md-source__fact {\n display: inline-block;\n}\n[data-md-state=done] .md-source__fact {\n animation: fact 400ms ease-out;\n}\n.md-source__fact::before {\n display: inline-block;\n width: 0.6rem;\n height: 0.6rem;\n margin-right: 0.1rem;\n vertical-align: text-top;\n background-color: currentColor;\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n.md-source__fact:nth-child(1n+2)::before {\n margin-left: 0.4rem;\n}\n[dir=rtl] .md-source__fact {\n margin-right: initial;\n margin-left: 0.1rem;\n}\n[dir=rtl] .md-source__fact:nth-child(1n+2)::before {\n margin-right: 0.4rem;\n margin-left: initial;\n}\n.md-source__fact--version::before {\n mask-image: var(--md-source-version-icon);\n}\n.md-source__fact--stars::before {\n mask-image: var(--md-source-stars-icon);\n}\n.md-source__fact--forks::before {\n mask-image: var(--md-source-forks-icon);\n}\n.md-source__fact--repositories::before {\n mask-image: var(--md-source-repositories-icon);\n}\n\n.md-tabs {\n width: 100%;\n overflow: auto;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n}\n@media print {\n .md-tabs {\n display: none;\n }\n}\n@media screen and (max-width: 76.1875em) {\n .md-tabs {\n display: none;\n }\n}\n.md-tabs[data-md-state=hidden] {\n pointer-events: none;\n}\n.md-tabs__list {\n margin: 0;\n margin-left: 0.2rem;\n padding: 0;\n white-space: nowrap;\n list-style: none;\n contain: content;\n}\n[dir=rtl] .md-tabs__list {\n margin-right: 0.2rem;\n margin-left: initial;\n}\n.md-tabs__item {\n display: inline-block;\n height: 2.4rem;\n padding-right: 0.6rem;\n padding-left: 0.6rem;\n}\n.md-tabs__link {\n display: block;\n margin-top: 0.8rem;\n font-size: 0.7rem;\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n backface-visibility: hidden;\n opacity: 0.7;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 250ms;\n}\n.md-tabs__link--active, .md-tabs__link:focus, .md-tabs__link:hover {\n color: inherit;\n opacity: 1;\n}\n.md-tabs__item:nth-child(2) .md-tabs__link {\n transition-delay: 20ms;\n}\n.md-tabs__item:nth-child(3) .md-tabs__link {\n transition-delay: 40ms;\n}\n.md-tabs__item:nth-child(4) .md-tabs__link {\n transition-delay: 60ms;\n}\n.md-tabs__item:nth-child(5) .md-tabs__link {\n transition-delay: 80ms;\n}\n.md-tabs__item:nth-child(6) .md-tabs__link {\n transition-delay: 100ms;\n}\n.md-tabs__item:nth-child(7) .md-tabs__link {\n transition-delay: 120ms;\n}\n.md-tabs__item:nth-child(8) .md-tabs__link {\n transition-delay: 140ms;\n}\n.md-tabs__item:nth-child(9) .md-tabs__link {\n transition-delay: 160ms;\n}\n.md-tabs__item:nth-child(10) .md-tabs__link {\n transition-delay: 180ms;\n}\n.md-tabs__item:nth-child(11) .md-tabs__link {\n transition-delay: 200ms;\n}\n.md-tabs__item:nth-child(12) .md-tabs__link {\n transition-delay: 220ms;\n}\n.md-tabs__item:nth-child(13) .md-tabs__link {\n transition-delay: 240ms;\n}\n.md-tabs__item:nth-child(14) .md-tabs__link {\n transition-delay: 260ms;\n}\n.md-tabs__item:nth-child(15) .md-tabs__link {\n transition-delay: 280ms;\n}\n.md-tabs__item:nth-child(16) .md-tabs__link {\n transition-delay: 300ms;\n}\n.md-tabs[data-md-state=hidden] .md-tabs__link {\n transform: translateY(50%);\n opacity: 0;\n transition: transform 0ms 100ms, opacity 100ms;\n}\n\n.md-top {\n position: fixed;\n top: 3.2rem;\n z-index: 2;\n margin-left: 50%;\n padding: 0.4rem 0.8rem;\n color: var(--md-default-fg-color--light);\n font-size: 0.7rem;\n background-color: var(--md-default-bg-color);\n border-radius: 1.6rem;\n outline: none;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n transform: translate(-50%, 0);\n transition: color 125ms, background-color 125ms, transform 125ms cubic-bezier(0.4, 0, 0.2, 1), opacity 125ms;\n}\n@media print {\n .md-top {\n display: none;\n }\n}\n[dir=rtl] .md-top {\n float: left;\n}\n.md-top[data-md-state=hidden] {\n transform: translate(-50%, 0.2rem);\n opacity: 0;\n transition-duration: 0ms;\n pointer-events: none;\n}\n.md-top:focus, .md-top:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n}\n.md-top svg {\n display: inline-block;\n vertical-align: -0.5em;\n}\n\n@keyframes hoverfix {\n 0% {\n pointer-events: none;\n }\n}\n:root {\n --md-version-icon: svg-load(\"fontawesome/solid/caret-down.svg\");\n}\n\n.md-version {\n flex-shrink: 0;\n height: 2.4rem;\n font-size: 0.8rem;\n}\n.md-version__current {\n position: relative;\n top: 0.05rem;\n margin-right: 0.4rem;\n margin-left: 1.4rem;\n color: inherit;\n outline: none;\n cursor: pointer;\n}\n[dir=rtl] .md-version__current {\n margin-right: 1.4rem;\n margin-left: 0.4rem;\n}\n.md-version__current::after {\n display: inline-block;\n width: 0.4rem;\n height: 0.6rem;\n margin-left: 0.4rem;\n background-color: currentColor;\n mask-image: var(--md-version-icon);\n mask-repeat: no-repeat;\n content: \"\";\n}\n[dir=rtl] .md-version__current::after {\n margin-right: 0.4rem;\n margin-left: initial;\n}\n.md-version__list {\n position: absolute;\n top: 0.15rem;\n z-index: 1;\n max-height: 0;\n margin: 0.2rem 0.8rem;\n padding: 0;\n overflow: auto;\n color: var(--md-default-fg-color);\n list-style-type: none;\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n opacity: 0;\n transition: max-height 0ms 500ms, opacity 250ms 250ms;\n scroll-snap-type: y mandatory;\n}\n.md-version:focus-within .md-version__list, .md-version:hover .md-version__list {\n max-height: 10rem;\n opacity: 1;\n transition: max-height 0ms, opacity 250ms;\n}\n@media (pointer: coarse) {\n .md-version:hover .md-version__list {\n animation: hoverfix 250ms forwards;\n }\n .md-version:focus-within .md-version__list {\n animation: none;\n }\n}\n.md-version__item {\n line-height: 1.8rem;\n}\n.md-version__link {\n display: block;\n width: 100%;\n padding-right: 1.2rem;\n padding-left: 0.6rem;\n white-space: nowrap;\n outline: none;\n cursor: pointer;\n transition: color 250ms, background-color 250ms;\n scroll-snap-align: start;\n}\n[dir=rtl] .md-version__link {\n padding-right: 0.6rem;\n padding-left: 1.2rem;\n}\n.md-version__link:focus, .md-version__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-version__link:focus {\n background-color: var(--md-default-fg-color--lightest);\n}\n\n:root {\n --md-admonition-icon--note:\n svg-load(\"material/pencil.svg\");\n --md-admonition-icon--abstract:\n svg-load(\"material/text-subject.svg\");\n --md-admonition-icon--info:\n svg-load(\"material/information.svg\");\n --md-admonition-icon--tip:\n svg-load(\"material/fire.svg\");\n --md-admonition-icon--success:\n svg-load(\"material/check-circle.svg\");\n --md-admonition-icon--question:\n svg-load(\"material/help-circle.svg\");\n --md-admonition-icon--warning:\n svg-load(\"material/alert.svg\");\n --md-admonition-icon--failure:\n svg-load(\"material/close-circle.svg\");\n --md-admonition-icon--danger:\n svg-load(\"material/flash-circle.svg\");\n --md-admonition-icon--bug:\n svg-load(\"material/bug.svg\");\n --md-admonition-icon--example:\n svg-load(\"material/format-list-numbered.svg\");\n --md-admonition-icon--quote:\n svg-load(\"material/format-quote-close.svg\");\n}\n\n.md-typeset .admonition, .md-typeset details {\n margin: 1.5625em 0;\n padding: 0 0.6rem;\n overflow: hidden;\n color: var(--md-admonition-fg-color);\n font-size: 0.64rem;\n page-break-inside: avoid;\n background-color: var(--md-admonition-bg-color);\n border-left: 0.2rem solid #448aff;\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.05);\n}\n@media print {\n .md-typeset .admonition, .md-typeset details {\n box-shadow: none;\n }\n}\n[dir=rtl] .md-typeset .admonition, [dir=rtl] .md-typeset details {\n border-right: 0.2rem solid #448aff;\n border-left: none;\n}\n.md-typeset .admonition .admonition, .md-typeset details .admonition, .md-typeset .admonition details, .md-typeset details details {\n margin-top: 1em;\n margin-bottom: 1em;\n}\n.md-typeset .admonition .md-typeset__scrollwrap, .md-typeset details .md-typeset__scrollwrap {\n margin: 1em -0.6rem;\n}\n.md-typeset .admonition .md-typeset__table, .md-typeset details .md-typeset__table {\n padding: 0 0.6rem;\n}\n.md-typeset .admonition > .tabbed-set:only-child, .md-typeset details > .tabbed-set:only-child {\n margin-top: 0;\n}\nhtml .md-typeset .admonition > :last-child, html .md-typeset details > :last-child {\n margin-bottom: 0.6rem;\n}\n.md-typeset .admonition-title, .md-typeset summary {\n position: relative;\n margin: 0 -0.6rem 0 -0.8rem;\n padding: 0.4rem 0.6rem 0.4rem 2rem;\n font-weight: 700;\n background-color: rgba(68, 138, 255, 0.1);\n border-left: 0.2rem solid #448aff;\n}\n[dir=rtl] .md-typeset .admonition-title, [dir=rtl] .md-typeset summary {\n margin: 0 -0.8rem 0 -0.6rem;\n padding: 0.4rem 2rem 0.4rem 0.6rem;\n border-right: 0.2rem solid #448aff;\n border-left: none;\n}\nhtml .md-typeset .admonition-title:last-child, html .md-typeset summary:last-child {\n margin-bottom: 0;\n}\n.md-typeset .admonition-title::before, .md-typeset summary::before {\n position: absolute;\n left: 0.6rem;\n width: 1rem;\n height: 1rem;\n background-color: #448aff;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .admonition-title::before, [dir=rtl] .md-typeset summary::before {\n right: 0.6rem;\n left: initial;\n}\n.md-typeset .admonition-title + .tabbed-set:last-child, .md-typeset summary + .tabbed-set:last-child {\n margin-top: 0;\n}\n\n.md-typeset .admonition.note, .md-typeset details.note {\n border-color: #448aff;\n}\n\n.md-typeset .note > .admonition-title, .md-typeset .note > summary {\n background-color: rgba(68, 138, 255, 0.1);\n border-color: #448aff;\n}\n.md-typeset .note > .admonition-title::before, .md-typeset .note > summary::before {\n background-color: #448aff;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.abstract, .md-typeset details.abstract, .md-typeset .admonition.tldr, .md-typeset details.tldr, .md-typeset .admonition.summary, .md-typeset details.summary {\n border-color: #00b0ff;\n}\n\n.md-typeset .abstract > .admonition-title, .md-typeset .abstract > summary, .md-typeset .tldr > .admonition-title, .md-typeset .tldr > summary, .md-typeset .summary > .admonition-title, .md-typeset .summary > summary {\n background-color: rgba(0, 176, 255, 0.1);\n border-color: #00b0ff;\n}\n.md-typeset .abstract > .admonition-title::before, .md-typeset .abstract > summary::before, .md-typeset .tldr > .admonition-title::before, .md-typeset .tldr > summary::before, .md-typeset .summary > .admonition-title::before, .md-typeset .summary > summary::before {\n background-color: #00b0ff;\n mask-image: var(--md-admonition-icon--abstract);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.info, .md-typeset details.info, .md-typeset .admonition.todo, .md-typeset details.todo {\n border-color: #00b8d4;\n}\n\n.md-typeset .info > .admonition-title, .md-typeset .info > summary, .md-typeset .todo > .admonition-title, .md-typeset .todo > summary {\n background-color: rgba(0, 184, 212, 0.1);\n border-color: #00b8d4;\n}\n.md-typeset .info > .admonition-title::before, .md-typeset .info > summary::before, .md-typeset .todo > .admonition-title::before, .md-typeset .todo > summary::before {\n background-color: #00b8d4;\n mask-image: var(--md-admonition-icon--info);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.tip, .md-typeset details.tip, .md-typeset .admonition.important, .md-typeset details.important, .md-typeset .admonition.hint, .md-typeset details.hint {\n border-color: #00bfa5;\n}\n\n.md-typeset .tip > .admonition-title, .md-typeset .tip > summary, .md-typeset .important > .admonition-title, .md-typeset .important > summary, .md-typeset .hint > .admonition-title, .md-typeset .hint > summary {\n background-color: rgba(0, 191, 165, 0.1);\n border-color: #00bfa5;\n}\n.md-typeset .tip > .admonition-title::before, .md-typeset .tip > summary::before, .md-typeset .important > .admonition-title::before, .md-typeset .important > summary::before, .md-typeset .hint > .admonition-title::before, .md-typeset .hint > summary::before {\n background-color: #00bfa5;\n mask-image: var(--md-admonition-icon--tip);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.success, .md-typeset details.success, .md-typeset .admonition.done, .md-typeset details.done, .md-typeset .admonition.check, .md-typeset details.check {\n border-color: #00c853;\n}\n\n.md-typeset .success > .admonition-title, .md-typeset .success > summary, .md-typeset .done > .admonition-title, .md-typeset .done > summary, .md-typeset .check > .admonition-title, .md-typeset .check > summary {\n background-color: rgba(0, 200, 83, 0.1);\n border-color: #00c853;\n}\n.md-typeset .success > .admonition-title::before, .md-typeset .success > summary::before, .md-typeset .done > .admonition-title::before, .md-typeset .done > summary::before, .md-typeset .check > .admonition-title::before, .md-typeset .check > summary::before {\n background-color: #00c853;\n mask-image: var(--md-admonition-icon--success);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.question, .md-typeset details.question, .md-typeset .admonition.faq, .md-typeset details.faq, .md-typeset .admonition.help, .md-typeset details.help {\n border-color: #64dd17;\n}\n\n.md-typeset .question > .admonition-title, .md-typeset .question > summary, .md-typeset .faq > .admonition-title, .md-typeset .faq > summary, .md-typeset .help > .admonition-title, .md-typeset .help > summary {\n background-color: rgba(100, 221, 23, 0.1);\n border-color: #64dd17;\n}\n.md-typeset .question > .admonition-title::before, .md-typeset .question > summary::before, .md-typeset .faq > .admonition-title::before, .md-typeset .faq > summary::before, .md-typeset .help > .admonition-title::before, .md-typeset .help > summary::before {\n background-color: #64dd17;\n mask-image: var(--md-admonition-icon--question);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.warning, .md-typeset details.warning, .md-typeset .admonition.attention, .md-typeset details.attention, .md-typeset .admonition.caution, .md-typeset details.caution {\n border-color: #ff9100;\n}\n\n.md-typeset .warning > .admonition-title, .md-typeset .warning > summary, .md-typeset .attention > .admonition-title, .md-typeset .attention > summary, .md-typeset .caution > .admonition-title, .md-typeset .caution > summary {\n background-color: rgba(255, 145, 0, 0.1);\n border-color: #ff9100;\n}\n.md-typeset .warning > .admonition-title::before, .md-typeset .warning > summary::before, .md-typeset .attention > .admonition-title::before, .md-typeset .attention > summary::before, .md-typeset .caution > .admonition-title::before, .md-typeset .caution > summary::before {\n background-color: #ff9100;\n mask-image: var(--md-admonition-icon--warning);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.failure, .md-typeset details.failure, .md-typeset .admonition.missing, .md-typeset details.missing, .md-typeset .admonition.fail, .md-typeset details.fail {\n border-color: #ff5252;\n}\n\n.md-typeset .failure > .admonition-title, .md-typeset .failure > summary, .md-typeset .missing > .admonition-title, .md-typeset .missing > summary, .md-typeset .fail > .admonition-title, .md-typeset .fail > summary {\n background-color: rgba(255, 82, 82, 0.1);\n border-color: #ff5252;\n}\n.md-typeset .failure > .admonition-title::before, .md-typeset .failure > summary::before, .md-typeset .missing > .admonition-title::before, .md-typeset .missing > summary::before, .md-typeset .fail > .admonition-title::before, .md-typeset .fail > summary::before {\n background-color: #ff5252;\n mask-image: var(--md-admonition-icon--failure);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.danger, .md-typeset details.danger, .md-typeset .admonition.error, .md-typeset details.error {\n border-color: #ff1744;\n}\n\n.md-typeset .danger > .admonition-title, .md-typeset .danger > summary, .md-typeset .error > .admonition-title, .md-typeset .error > summary {\n background-color: rgba(255, 23, 68, 0.1);\n border-color: #ff1744;\n}\n.md-typeset .danger > .admonition-title::before, .md-typeset .danger > summary::before, .md-typeset .error > .admonition-title::before, .md-typeset .error > summary::before {\n background-color: #ff1744;\n mask-image: var(--md-admonition-icon--danger);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.bug, .md-typeset details.bug {\n border-color: #f50057;\n}\n\n.md-typeset .bug > .admonition-title, .md-typeset .bug > summary {\n background-color: rgba(245, 0, 87, 0.1);\n border-color: #f50057;\n}\n.md-typeset .bug > .admonition-title::before, .md-typeset .bug > summary::before {\n background-color: #f50057;\n mask-image: var(--md-admonition-icon--bug);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.example, .md-typeset details.example {\n border-color: #7c4dff;\n}\n\n.md-typeset .example > .admonition-title, .md-typeset .example > summary {\n background-color: rgba(124, 77, 255, 0.1);\n border-color: #7c4dff;\n}\n.md-typeset .example > .admonition-title::before, .md-typeset .example > summary::before {\n background-color: #7c4dff;\n mask-image: var(--md-admonition-icon--example);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.quote, .md-typeset details.quote, .md-typeset .admonition.cite, .md-typeset details.cite {\n border-color: #9e9e9e;\n}\n\n.md-typeset .quote > .admonition-title, .md-typeset .quote > summary, .md-typeset .cite > .admonition-title, .md-typeset .cite > summary {\n background-color: rgba(158, 158, 158, 0.1);\n border-color: #9e9e9e;\n}\n.md-typeset .quote > .admonition-title::before, .md-typeset .quote > summary::before, .md-typeset .cite > .admonition-title::before, .md-typeset .cite > summary::before {\n background-color: #9e9e9e;\n mask-image: var(--md-admonition-icon--quote);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n:root {\n --md-footnotes-icon: svg-load(\"material/keyboard-return.svg\");\n}\n\n.md-typeset .footnote {\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n}\n.md-typeset .footnote > ol {\n margin-left: 0;\n}\n.md-typeset .footnote > ol > li {\n transition: color 125ms;\n}\n.md-typeset .footnote > ol > li:target {\n color: var(--md-default-fg-color);\n}\n.md-typeset .footnote > ol > li:hover .footnote-backref, .md-typeset .footnote > ol > li:target .footnote-backref {\n transform: translateX(0);\n opacity: 1;\n}\n.md-typeset .footnote > ol > li > :first-child {\n margin-top: 0;\n}\n.md-typeset .footnote-ref {\n font-weight: 700;\n font-size: 0.75em;\n}\nhtml .md-typeset .footnote-ref {\n outline-offset: 0.1rem;\n}\n.md-typeset .footnote-backref {\n display: inline-block;\n color: var(--md-typeset-a-color);\n font-size: 0;\n vertical-align: text-bottom;\n transform: translateX(0.25rem);\n opacity: 0;\n transition: color 250ms, transform 250ms 250ms, opacity 125ms 250ms;\n}\n@media print {\n .md-typeset .footnote-backref {\n color: var(--md-typeset-a-color);\n transform: translateX(0);\n opacity: 1;\n }\n}\n[dir=rtl] .md-typeset .footnote-backref {\n transform: translateX(-0.25rem);\n}\n.md-typeset .footnote-backref:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset .footnote-backref::before {\n display: inline-block;\n width: 0.8rem;\n height: 0.8rem;\n background-color: currentColor;\n mask-image: var(--md-footnotes-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .footnote-backref::before svg {\n transform: scaleX(-1);\n}\n.md-typeset [id^=\"fnref:\"]:target {\n scroll-margin-top: initial;\n margin-top: -3.4rem;\n padding-top: 3.4rem;\n}\n.md-typeset [id^=\"fnref:\"]:target > .footnote-ref {\n outline: auto;\n}\n.md-typeset [id^=\"fn:\"]:target {\n scroll-margin-top: initial;\n margin-top: -3.45rem;\n padding-top: 3.45rem;\n}\n\n.md-typeset .headerlink {\n display: inline-block;\n margin-left: 0.5rem;\n color: var(--md-default-fg-color--lighter);\n opacity: 0;\n transition: color 250ms, opacity 125ms;\n}\n@media print {\n .md-typeset .headerlink {\n display: none;\n }\n}\n[dir=rtl] .md-typeset .headerlink {\n margin-right: 0.5rem;\n margin-left: initial;\n}\n.md-typeset :hover > .headerlink,\n.md-typeset :target > .headerlink,\n.md-typeset .headerlink:focus {\n opacity: 1;\n transition: color 250ms, opacity 125ms;\n}\n.md-typeset :target > .headerlink,\n.md-typeset .headerlink:focus,\n.md-typeset .headerlink:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset :target {\n scroll-margin-top: 3.6rem;\n}\n.md-typeset h1:target,\n.md-typeset h2:target,\n.md-typeset h3:target {\n scroll-margin-top: initial;\n}\n.md-typeset h1:target::before,\n.md-typeset h2:target::before,\n.md-typeset h3:target::before {\n display: block;\n margin-top: -3.4rem;\n padding-top: 3.4rem;\n content: \"\";\n}\n.md-typeset h4:target {\n scroll-margin-top: initial;\n}\n.md-typeset h4:target::before {\n display: block;\n margin-top: -3.45rem;\n padding-top: 3.45rem;\n content: \"\";\n}\n.md-typeset h5:target,\n.md-typeset h6:target {\n scroll-margin-top: initial;\n}\n.md-typeset h5:target::before,\n.md-typeset h6:target::before {\n display: block;\n margin-top: -3.6rem;\n padding-top: 3.6rem;\n content: \"\";\n}\n\n.md-typeset div.arithmatex {\n overflow: auto;\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset div.arithmatex {\n margin: 0 -0.8rem;\n }\n}\n.md-typeset div.arithmatex > * {\n width: min-content;\n margin: 1em auto !important;\n padding: 0 0.8rem;\n touch-action: auto;\n}\n\n.md-typeset del.critic,\n.md-typeset ins.critic,\n.md-typeset .critic.comment {\n box-decoration-break: clone;\n}\n.md-typeset del.critic {\n background-color: var(--md-typeset-del-color);\n}\n.md-typeset ins.critic {\n background-color: var(--md-typeset-ins-color);\n}\n.md-typeset .critic.comment {\n color: var(--md-code-hl-comment-color);\n}\n.md-typeset .critic.comment::before {\n content: \"/* \";\n}\n.md-typeset .critic.comment::after {\n content: \" */\";\n}\n.md-typeset .critic.block {\n display: block;\n margin: 1em 0;\n padding-right: 0.8rem;\n padding-left: 0.8rem;\n overflow: auto;\n box-shadow: none;\n}\n.md-typeset .critic.block > :first-child {\n margin-top: 0.5em;\n}\n.md-typeset .critic.block > :last-child {\n margin-bottom: 0.5em;\n}\n\n:root {\n --md-details-icon: svg-load(\"material/chevron-right.svg\");\n}\n\n.md-typeset details {\n display: flow-root;\n padding-top: 0;\n overflow: visible;\n}\n.md-typeset details[open] > summary::after {\n transform: rotate(90deg);\n}\n.md-typeset details:not([open]) {\n padding-bottom: 0;\n box-shadow: none;\n}\n.md-typeset details:not([open]) > summary {\n border-radius: 0.1rem;\n}\n.md-typeset details::after {\n display: table;\n content: \"\";\n}\n.md-typeset summary {\n display: block;\n min-height: 1rem;\n padding: 0.4rem 1.8rem 0.4rem 2rem;\n border-top-left-radius: 0.1rem;\n border-top-right-radius: 0.1rem;\n cursor: pointer;\n}\n[dir=rtl] .md-typeset summary {\n padding: 0.4rem 2.2rem 0.4rem 1.8rem;\n}\n.md-typeset summary:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset summary::after {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n width: 1rem;\n height: 1rem;\n background-color: currentColor;\n mask-image: var(--md-details-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transform: rotate(0deg);\n transition: transform 250ms;\n content: \"\";\n}\n[dir=rtl] .md-typeset summary::after {\n right: initial;\n left: 0.4rem;\n transform: rotate(180deg);\n}\n.md-typeset summary::marker, .md-typeset summary::-webkit-details-marker {\n display: none;\n}\n\n.md-typeset .emojione,\n.md-typeset .twemoji,\n.md-typeset .gemoji {\n display: inline-flex;\n height: 1.125em;\n vertical-align: text-top;\n}\n.md-typeset .emojione svg,\n.md-typeset .twemoji svg,\n.md-typeset .gemoji svg {\n width: 1.125em;\n max-height: 100%;\n fill: currentColor;\n}\n\n.highlight .o,\n.highlight .ow {\n color: var(--md-code-hl-operator-color);\n}\n.highlight .p {\n color: var(--md-code-hl-punctuation-color);\n}\n.highlight .cpf,\n.highlight .l,\n.highlight .s,\n.highlight .sb,\n.highlight .sc,\n.highlight .s2,\n.highlight .si,\n.highlight .s1,\n.highlight .ss {\n color: var(--md-code-hl-string-color);\n}\n.highlight .cp,\n.highlight .se,\n.highlight .sh,\n.highlight .sr,\n.highlight .sx {\n color: var(--md-code-hl-special-color);\n}\n.highlight .m,\n.highlight .mb,\n.highlight .mf,\n.highlight .mh,\n.highlight .mi,\n.highlight .il,\n.highlight .mo {\n color: var(--md-code-hl-number-color);\n}\n.highlight .k,\n.highlight .kd,\n.highlight .kn,\n.highlight .kp,\n.highlight .kr,\n.highlight .kt {\n color: var(--md-code-hl-keyword-color);\n}\n.highlight .kc,\n.highlight .n {\n color: var(--md-code-hl-name-color);\n}\n.highlight .no,\n.highlight .nb,\n.highlight .bp {\n color: var(--md-code-hl-constant-color);\n}\n.highlight .nc,\n.highlight .ne,\n.highlight .nf,\n.highlight .nn {\n color: var(--md-code-hl-function-color);\n}\n.highlight .nd,\n.highlight .ni,\n.highlight .nl,\n.highlight .nt {\n color: var(--md-code-hl-keyword-color);\n}\n.highlight .c,\n.highlight .cm,\n.highlight .c1,\n.highlight .ch,\n.highlight .cs,\n.highlight .sd {\n color: var(--md-code-hl-comment-color);\n}\n.highlight .na,\n.highlight .nv,\n.highlight .vc,\n.highlight .vg,\n.highlight .vi {\n color: var(--md-code-hl-variable-color);\n}\n.highlight .ge,\n.highlight .gr,\n.highlight .gh,\n.highlight .go,\n.highlight .gp,\n.highlight .gs,\n.highlight .gu,\n.highlight .gt {\n color: var(--md-code-hl-generic-color);\n}\n.highlight .gd,\n.highlight .gi {\n margin: 0 -0.125em;\n padding: 0 0.125em;\n border-radius: 0.1rem;\n}\n.highlight .gd {\n background-color: var(--md-typeset-del-color);\n}\n.highlight .gi {\n background-color: var(--md-typeset-ins-color);\n}\n.highlight .hll {\n display: block;\n margin: 0 -1.1764705882em;\n padding: 0 1.1764705882em;\n background-color: var(--md-code-hl-color);\n}\n.highlight [data-linenos]::before {\n position: sticky;\n left: -1.1764705882em;\n float: left;\n margin-right: 1.1764705882em;\n margin-left: -1.1764705882em;\n padding-left: 1.1764705882em;\n color: var(--md-default-fg-color--light);\n background-color: var(--md-code-bg-color);\n box-shadow: -0.05rem 0 var(--md-default-fg-color--lightest) inset;\n content: attr(data-linenos);\n user-select: none;\n}\n\n.highlighttable {\n display: flow-root;\n overflow: hidden;\n}\n.highlighttable tbody,\n.highlighttable td {\n display: block;\n padding: 0;\n}\n.highlighttable tr {\n display: flex;\n}\n.highlighttable pre {\n margin: 0;\n}\n.highlighttable .linenos {\n padding: 0.7720588235em 1.1764705882em;\n padding-right: 0;\n font-size: 0.85em;\n background-color: var(--md-code-bg-color);\n user-select: none;\n}\n.highlighttable .linenodiv {\n padding-right: 0.5882352941em;\n box-shadow: -0.05rem 0 var(--md-default-fg-color--lightest) inset;\n}\n.highlighttable .linenodiv pre {\n color: var(--md-default-fg-color--light);\n text-align: right;\n}\n.highlighttable .code {\n flex: 1;\n overflow: hidden;\n}\n\n.md-typeset .highlighttable {\n margin: 1em 0;\n direction: ltr;\n border-radius: 0.1rem;\n}\n.md-typeset .highlighttable code {\n border-radius: 0;\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset > .highlight {\n margin: 1em -0.8rem;\n }\n .md-typeset > .highlight .hll {\n margin: 0 -0.8rem;\n padding: 0 0.8rem;\n }\n .md-typeset > .highlight code {\n border-radius: 0;\n }\n .md-typeset > .highlighttable {\n margin: 1em -0.8rem;\n border-radius: 0;\n }\n .md-typeset > .highlighttable .hll {\n margin: 0 -0.8rem;\n padding: 0 0.8rem;\n }\n}\n\n.md-typeset .keys kbd::before,\n.md-typeset .keys kbd::after {\n position: relative;\n margin: 0;\n color: inherit;\n -moz-osx-font-smoothing: initial;\n -webkit-font-smoothing: initial;\n}\n.md-typeset .keys span {\n padding: 0 0.2em;\n color: var(--md-default-fg-color--light);\n}\n.md-typeset .keys .key-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-left-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-right-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-left-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-right-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-left-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-right-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-left-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-right-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-left-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-right-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-left-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-right-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-left-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-right-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-left-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-right-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-arrow-down::before {\n padding-right: 0.4em;\n content: \"↓\";\n}\n.md-typeset .keys .key-arrow-left::before {\n padding-right: 0.4em;\n content: \"←\";\n}\n.md-typeset .keys .key-arrow-right::before {\n padding-right: 0.4em;\n content: \"→\";\n}\n.md-typeset .keys .key-arrow-up::before {\n padding-right: 0.4em;\n content: \"↑\";\n}\n.md-typeset .keys .key-backspace::before {\n padding-right: 0.4em;\n content: \"⌫\";\n}\n.md-typeset .keys .key-backtab::before {\n padding-right: 0.4em;\n content: \"⇤\";\n}\n.md-typeset .keys .key-caps-lock::before {\n padding-right: 0.4em;\n content: \"⇪\";\n}\n.md-typeset .keys .key-clear::before {\n padding-right: 0.4em;\n content: \"⌧\";\n}\n.md-typeset .keys .key-context-menu::before {\n padding-right: 0.4em;\n content: \"☰\";\n}\n.md-typeset .keys .key-delete::before {\n padding-right: 0.4em;\n content: \"⌦\";\n}\n.md-typeset .keys .key-eject::before {\n padding-right: 0.4em;\n content: \"⏏\";\n}\n.md-typeset .keys .key-end::before {\n padding-right: 0.4em;\n content: \"⤓\";\n}\n.md-typeset .keys .key-escape::before {\n padding-right: 0.4em;\n content: \"⎋\";\n}\n.md-typeset .keys .key-home::before {\n padding-right: 0.4em;\n content: \"⤒\";\n}\n.md-typeset .keys .key-insert::before {\n padding-right: 0.4em;\n content: \"⎀\";\n}\n.md-typeset .keys .key-page-down::before {\n padding-right: 0.4em;\n content: \"⇟\";\n}\n.md-typeset .keys .key-page-up::before {\n padding-right: 0.4em;\n content: \"⇞\";\n}\n.md-typeset .keys .key-print-screen::before {\n padding-right: 0.4em;\n content: \"⎙\";\n}\n.md-typeset .keys .key-tab::after {\n padding-left: 0.4em;\n content: \"⇥\";\n}\n.md-typeset .keys .key-num-enter::after {\n padding-left: 0.4em;\n content: \"⌤\";\n}\n.md-typeset .keys .key-enter::after {\n padding-left: 0.4em;\n content: \"⏎\";\n}\n\n.md-typeset .tabbed-content {\n display: none;\n order: 99;\n width: 100%;\n box-shadow: 0 -0.05rem var(--md-default-fg-color--lightest);\n}\n@media print {\n .md-typeset .tabbed-content {\n display: block;\n order: initial;\n }\n}\n.md-typeset .tabbed-content > pre:only-child,\n.md-typeset .tabbed-content > .highlight:only-child pre,\n.md-typeset .tabbed-content > .highlighttable:only-child {\n margin: 0;\n}\n.md-typeset .tabbed-content > pre:only-child > code,\n.md-typeset .tabbed-content > .highlight:only-child pre > code,\n.md-typeset .tabbed-content > .highlighttable:only-child > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.md-typeset .tabbed-content > .tabbed-set {\n margin: 0;\n}\n.md-typeset .tabbed-set {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n margin: 1em 0;\n border-radius: 0.1rem;\n}\n.md-typeset .tabbed-set > input {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n}\n.md-typeset .tabbed-set > input:checked + label {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n}\n.md-typeset .tabbed-set > input:checked + label + .tabbed-content {\n display: block;\n}\n.md-typeset .tabbed-set > input:focus + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n}\n.md-typeset .tabbed-set > input:not(.focus-visible) + label {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset .tabbed-set > label {\n z-index: 1;\n width: auto;\n padding: 0.9375em 1.25em 0.78125em;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: 0.64rem;\n border-bottom: 0.1rem solid transparent;\n cursor: pointer;\n transition: color 250ms;\n}\n.md-typeset .tabbed-set > label:hover {\n color: var(--md-accent-fg-color);\n}\n\n:root {\n --md-tasklist-icon:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n --md-tasklist-icon--checked:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n}\n\n.md-typeset .task-list-item {\n position: relative;\n list-style-type: none;\n}\n.md-typeset .task-list-item [type=checkbox] {\n position: absolute;\n top: 0.45em;\n left: -2em;\n}\n[dir=rtl] .md-typeset .task-list-item [type=checkbox] {\n right: -2em;\n left: initial;\n}\n.md-typeset .task-list-control [type=checkbox] {\n z-index: -1;\n opacity: 0;\n}\n.md-typeset .task-list-indicator::before {\n position: absolute;\n top: 0.15em;\n left: -1.5em;\n width: 1.25em;\n height: 1.25em;\n background-color: var(--md-default-fg-color--lightest);\n mask-image: var(--md-tasklist-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .task-list-indicator::before {\n right: -1.5em;\n left: initial;\n}\n.md-typeset [type=checkbox]:checked + .task-list-indicator::before {\n background-color: #00e676;\n mask-image: var(--md-tasklist-icon--checked);\n}\n\n@media screen and (min-width: 45em) {\n .md-typeset .inline {\n float: left;\n width: 11.7rem;\n margin-top: 0;\n margin-right: 0.8rem;\n margin-bottom: 0.8rem;\n }\n [dir=rtl] .md-typeset .inline {\n float: right;\n margin-right: 0;\n margin-left: 0.8rem;\n }\n .md-typeset .inline.end {\n float: right;\n margin-right: 0;\n margin-left: 0.8rem;\n }\n [dir=rtl] .md-typeset .inline.end {\n float: left;\n margin-right: 0.8rem;\n margin-left: 0;\n }\n}\n\n/*# sourceMappingURL=main.css.map */","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Enforce correct box model and prevent adjustments of font size after\n// orientation changes in IE and iOS\nhtml {\n box-sizing: border-box;\n text-size-adjust: none;\n}\n\n// All elements shall inherit the document default\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n// Remove margin in all browsers\nbody {\n margin: 0;\n}\n\n// Reset tap outlines on iOS and Android\na,\nbutton,\nlabel,\ninput {\n -webkit-tap-highlight-color: transparent;\n}\n\n// Reset link styles\na {\n color: inherit;\n text-decoration: none;\n}\n\n// Normalize horizontal separator styles\nhr {\n display: block;\n box-sizing: content-box;\n height: px2rem(1px);\n padding: 0;\n overflow: visible;\n border: 0;\n}\n\n// Normalize font-size in all browsers\nsmall {\n font-size: 80%;\n}\n\n// Prevent subscript and superscript from affecting line-height\nsub,\nsup {\n line-height: 1em;\n}\n\n// Remove border on image\nimg {\n border-style: none;\n}\n\n// Reset table styles\ntable {\n border-collapse: separate;\n border-spacing: 0;\n}\n\n// Reset table cell styles\ntd,\nth {\n font-weight: 400;\n vertical-align: top;\n}\n\n// Reset button styles\nbutton {\n margin: 0;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n background: transparent;\n border: 0;\n}\n\n// Reset input styles\ninput {\n border: 0;\n outline: none;\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Color definitions\n:root {\n\n // Default color shades\n --md-default-fg-color: hsla(0, 0%, 0%, 0.87);\n --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32);\n --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07);\n --md-default-bg-color: hsla(0, 0%, 100%, 1);\n --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12);\n\n // Primary color shades\n --md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n --md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1);\n --md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Accent color shades\n --md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1);\n --md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Light theme (default)\n > * {\n\n // Code color shades\n --md-code-fg-color: hsla(200, 18%, 26%, 1);\n --md-code-bg-color: hsla(0, 0%, 96%, 1);\n\n // Code highlighting color shades\n --md-code-hl-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);\n --md-code-hl-number-color: hsla(0, 67%, 50%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 47%, 1);\n --md-code-hl-function-color: hsla(291, 45%, 50%, 1);\n --md-code-hl-constant-color: hsla(250, 63%, 60%, 1);\n --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1);\n --md-code-hl-string-color: hsla(150, 63%, 30%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n\n // Typeset color shades\n --md-typeset-color: var(--md-default-fg-color);\n\n // Typeset `a` color shades\n --md-typeset-a-color: var(--md-primary-fg-color);\n\n // Typeset `mark` color shades\n --md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);\n\n // Typeset `del` and `ins` color shades\n --md-typeset-del-color: hsla(6, 90%, 60%, 0.15);\n --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15);\n\n // Typeset `kbd` color shades\n --md-typeset-kbd-color: hsla(0, 0%, 98%, 1);\n --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);\n --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1);\n\n // Typeset `table` color shades\n --md-typeset-table-color: hsla(0, 0%, 0%, 0.12);\n\n // Admonition color shades\n --md-admonition-fg-color: var(--md-default-fg-color);\n --md-admonition-bg-color: var(--md-default-bg-color);\n\n // Footer color shades\n --md-footer-fg-color: hsla(0, 0%, 100%, 1);\n --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-footer-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon\n.md-icon {\n\n // SVG defaults\n svg {\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n fill: currentColor;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: font definitions\n// ----------------------------------------------------------------------------\n\n// Enable font-smoothing in Webkit and FF\nbody {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Define default fonts\nbody,\ninput {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\", \"liga\";\n font-family:\n var(--md-text-font-family, _),\n -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;\n}\n\n// Define monospaced fonts\ncode,\npre,\nkbd {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\";\n font-family:\n var(--md-code-font-family, _),\n SFMono-Regular, Consolas, Menlo, monospace;\n}\n\n// ----------------------------------------------------------------------------\n// Rules: typesetted content\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-typeset-table-sort-icon: svg-load(\"material/sort.svg\");\n --md-typeset-table-sort-icon--asc: svg-load(\"material/sort-ascending.svg\");\n --md-typeset-table-sort-icon--desc: svg-load(\"material/sort-descending.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Content that is typeset - if possible, all margins, paddings and font sizes\n// should be set in ems, so nested blocks (e.g. admonitions) render correctly.\n.md-typeset {\n font-size: px2rem(16px);\n line-height: 1.6;\n color-adjust: exact;\n\n // [print]: We'll use a smaller `font-size` for printing, so code examples\n // don't break too early, and `16px` looks too big anyway.\n @media print {\n font-size: px2rem(13.6px);\n }\n\n // Default spacing\n ul,\n ol,\n dl,\n figure,\n blockquote,\n pre {\n margin: 1em 0;\n }\n\n // Headline on level 1\n h1 {\n margin: 0 0 px2em(40px, 32px);\n color: var(--md-default-fg-color--light);\n font-weight: 300;\n font-size: px2em(32px);\n line-height: 1.3;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 2\n h2 {\n margin: px2em(40px, 25px) 0 px2em(16px, 25px);\n font-weight: 300;\n font-size: px2em(25px);\n line-height: 1.4;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 3\n h3 {\n margin: px2em(32px, 20px) 0 px2em(16px, 20px);\n font-weight: 400;\n font-size: px2em(20px);\n line-height: 1.5;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 3 following level 2\n h2 + h3 {\n margin-top: px2em(16px, 20px);\n }\n\n // Headline on level 4\n h4 {\n margin: px2em(16px) 0;\n font-weight: 700;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 5-6\n h5,\n h6 {\n margin: px2em(16px, 12.8px) 0;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: px2em(12.8px);\n letter-spacing: -0.01em;\n }\n\n // Headline on level 5\n h5 {\n text-transform: uppercase;\n }\n\n // Horizontal separator\n hr {\n display: flow-root;\n margin: 1.5em 0;\n border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest);\n }\n\n // Text link\n a {\n color: var(--md-typeset-a-color);\n word-break: break-word;\n\n // Also enable color transition on pseudo elements\n &,\n &::before {\n transition: color 125ms;\n }\n\n // Text link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Text link on keyboard focus\n &.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n }\n }\n\n // Code block\n code,\n pre,\n kbd {\n color: var(--md-code-fg-color);\n direction: ltr;\n\n // [print]: Wrap text and hide scollbars\n @media print {\n white-space: pre-wrap;\n }\n }\n\n // Inline code block\n code {\n padding: 0 px2em(4px, 13.6px);\n font-size: px2em(13.6px);\n word-break: break-word;\n background-color: var(--md-code-bg-color);\n border-radius: px2rem(2px);\n box-decoration-break: clone;\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n // Code block in headline\n h1 code,\n h2 code,\n h3 code,\n h4 code,\n h5 code,\n h6 code {\n margin: initial;\n padding: initial;\n background-color: transparent;\n box-shadow: none;\n }\n\n // Ensure link color in code blocks\n a code {\n color: currentColor;\n }\n\n // Unformatted content\n pre {\n position: relative;\n display: flow-root;\n line-height: 1.4;\n\n // Code block\n > code {\n display: block;\n margin: 0;\n padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);\n overflow: auto;\n word-break: normal;\n box-shadow: none;\n box-decoration-break: slice;\n touch-action: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Code block on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n }\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n\n // Unformatted text\n > pre {\n margin: 1em px2rem(-16px);\n\n // Code block\n code {\n border-radius: 0;\n }\n }\n }\n\n // Keyboard key\n kbd {\n display: inline-block;\n padding: 0 px2em(8px, 12px);\n color: var(--md-default-fg-color);\n font-size: px2em(12px);\n vertical-align: text-top;\n word-break: break-word;\n background-color: var(--md-typeset-kbd-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(2px) 0 px2rem(1px) var(--md-typeset-kbd-border-color),\n 0 px2rem(2px) 0 var(--md-typeset-kbd-border-color),\n 0 px2rem(-2px) px2rem(4px) var(--md-typeset-kbd-accent-color) inset;\n }\n\n // Text highlighting marker\n mark {\n color: inherit;\n word-break: break-word;\n background-color: var(--md-typeset-mark-color);\n box-decoration-break: clone;\n }\n\n // Abbreviation\n abbr {\n text-decoration: none;\n border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light);\n cursor: help;\n\n // Show tooltip for touch devices\n @media (hover: none) {\n position: relative;\n\n // Tooltip\n &[title]:focus::after,\n &[title]:hover::after {\n @include z-depth(2);\n\n position: absolute;\n left: 0;\n display: inline-block;\n width: auto;\n min-width: max-content;\n max-width: 80%;\n margin-top: 2em;\n padding: px2rem(4px) px2rem(6px);\n color: var(--md-default-bg-color);\n font-size: px2rem(14px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n content: attr(title);\n }\n }\n }\n\n // Small text\n small {\n opacity: 0.75;\n }\n\n // Superscript and subscript\n sup,\n sub {\n margin-left: px2em(1px, 12.8px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(1px, 12.8px);\n margin-left: initial;\n }\n }\n\n // Blockquotes, possibly nested\n blockquote {\n padding-left: px2rem(12px);\n color: var(--md-default-fg-color--light);\n border-left: px2rem(4px) solid var(--md-default-fg-color--lighter);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: initial;\n border-right: px2rem(4px) solid var(--md-default-fg-color--lighter);\n border-left: initial;\n }\n }\n\n // Unordered list\n ul {\n list-style-type: disc;\n }\n\n // Unordered and ordered list\n ul,\n ol {\n display: flow-root;\n margin-left: px2em(10px);\n padding: 0;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(10px);\n margin-left: initial;\n }\n\n // Nested ordered list\n ol {\n list-style-type: lower-alpha;\n\n // Triply nested ordered list\n ol {\n list-style-type: lower-roman;\n }\n }\n\n // List element\n li {\n margin-bottom: 0.5em;\n margin-left: px2em(20px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(20px);\n margin-left: initial;\n }\n\n // Adjust spacing\n p,\n blockquote {\n margin: 0.5em 0;\n }\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n\n // Nested list\n ul,\n ol {\n margin: 0.5em 0 0.5em px2em(10px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(10px);\n margin-left: initial;\n }\n }\n }\n }\n\n // Definition list\n dd {\n margin: 1em 0 1.5em px2em(30px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(30px);\n margin-left: initial;\n }\n }\n\n // Image or icon\n img,\n svg {\n max-width: 100%;\n height: auto;\n\n // Adjust spacing when left-aligned\n &[align=\"left\"] {\n margin: 1em;\n margin-left: 0;\n }\n\n // Adjust spacing when right-aligned\n &[align=\"right\"] {\n margin: 1em;\n margin-right: 0;\n }\n\n // Adjust spacing when sole children\n &[align]:only-child {\n margin-top: 0;\n }\n }\n\n // Figure\n figure {\n display: flow-root;\n width: fit-content;\n max-width: 100%;\n margin: 0 auto;\n text-align: center;\n\n // Figure images\n img {\n display: block;\n }\n }\n\n // Figure caption\n figcaption {\n max-width: px2rem(480px);\n margin: 1em auto 2em;\n font-style: italic;\n }\n\n // Limit width to container\n iframe {\n max-width: 100%;\n }\n\n // Data table\n table:not([class]) {\n display: inline-block;\n max-width: 100%;\n overflow: auto;\n font-size: px2rem(12.8px);\n background-color: var(--md-default-bg-color);\n border: px2rem(1px) solid var(--md-typeset-table-color);\n border-radius: px2rem(2px);\n touch-action: auto;\n\n // [print]: Reset display mode so table header wraps when printing\n @media print {\n display: table;\n }\n\n // Due to margin collapse because of the necessary inline-block hack, we\n // cannot increase the bottom margin on the table, so we just increase the\n // top margin on the following element\n + * {\n margin-top: 1.5em;\n }\n\n // Elements in table heading and cell\n th > *,\n td > * {\n\n // Adjust spacing on first child\n &:first-child {\n margin-top: 0;\n }\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Table heading and cell\n th:not([align]),\n td:not([align]) {\n text-align: left;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n text-align: right;\n }\n }\n\n // Table heading\n th {\n min-width: px2rem(100px);\n padding: px2em(12px, 12.8px) px2em(16px, 12.8px);\n font-weight: 700;\n vertical-align: top;\n\n // Links in table headings\n a {\n color: inherit;\n }\n }\n\n // Table cell\n td {\n padding: px2em(12px, 12.8px) px2em(16px, 12.8px);\n vertical-align: top;\n border-top: px2rem(1px) solid var(--md-typeset-table-color);\n }\n\n // Table body row\n tbody tr {\n transition: background-color 125ms;\n\n // Table row on hover\n &:hover {\n background-color: rgba(0, 0, 0, 0.035);\n box-shadow: 0 px2rem(1px) 0 var(--md-default-bg-color) inset;\n }\n }\n\n // Text link in table\n a {\n word-break: normal;\n }\n }\n\n // Sortable table\n table th[role=\"columnheader\"] {\n cursor: pointer;\n\n // Sort icon\n &::after {\n display: inline-block;\n width: 1.2em;\n height: 1.2em;\n margin-left: 0.5em;\n vertical-align: text-bottom;\n mask-image: var(--md-typeset-table-sort-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transition: background-color 125ms;\n content: \"\";\n }\n\n // Show sort icon on hover\n &:hover::after {\n background-color: var(--md-default-fg-color--lighter);\n }\n\n // Sort ascending icon\n &[aria-sort=\"ascending\"]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--asc);\n }\n\n // Sort descending icon\n &[aria-sort=\"descending\"]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--desc);\n }\n }\n\n // Data table scroll wrapper\n &__scrollwrap {\n margin: 1em px2rem(-16px);\n overflow-x: auto;\n touch-action: auto;\n }\n\n // Data table wrapper\n &__table {\n display: inline-block;\n margin-bottom: 0.5em;\n padding: 0 px2rem(16px);\n\n // [print]: Reset display mode so table header wraps when printing\n @media print {\n display: block;\n }\n\n // Data table\n html & table {\n display: table;\n width: 100%;\n margin: 0;\n overflow: hidden;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n///\n/// Device-specific breakpoints\n///\n/// @example\n/// $break-devices: (\n/// mobile: (\n/// portrait: 220px 479px,\n/// landscape: 480px 719px\n/// ),\n/// tablet: (\n/// portrait: 720px 959px,\n/// landscape: 960px 1219px\n/// ),\n/// screen: (\n/// small: 1220px 1599px,\n/// medium: 1600px 1999px,\n/// large: 2000px\n/// )\n/// );\n///\n$break-devices: () !default;\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n///\n/// Choose minimum and maximum device widths\n///\n@function break-select-min-max($devices) {\n $min: 1000000;\n $max: 0;\n @each $key, $value in $devices {\n @while type-of($value) == map {\n $value: break-select-min-max($value);\n }\n @if type-of($value) == list {\n @each $number in $value {\n @if type-of($number) == number {\n $min: min($number, $min);\n @if $max {\n $max: max($number, $max);\n }\n } @else {\n @error \"Invalid number: #{$number}\";\n }\n }\n } @else if type-of($value) == number {\n $min: min($value, $min);\n $max: null;\n } @else {\n @error \"Invalid value: #{$value}\";\n }\n }\n @return $min, $max;\n}\n\n///\n/// Select minimum and maximum widths for a device breakpoint\n///\n@function break-select-device($device) {\n $current: $break-devices;\n @for $n from 1 through length($device) {\n @if type-of($current) == map {\n $current: map-get($current, nth($device, $n));\n } @else {\n @error \"Invalid device map: #{$devices}\";\n }\n }\n @if type-of($current) == list or type-of($current) == number {\n $current: (default: $current);\n }\n @return break-select-min-max($current);\n}\n\n// ----------------------------------------------------------------------------\n// Mixins\n// ----------------------------------------------------------------------------\n\n///\n/// A minimum-maximum media query breakpoint\n///\n@mixin break-at($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (min-width: $breakpoint) {\n @content;\n }\n } @else if type-of($breakpoint) == list {\n $min: nth($breakpoint, 1);\n $max: nth($breakpoint, 2);\n @if type-of($min) == number and type-of($max) == number {\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// An orientation media query breakpoint\n///\n@mixin break-at-orientation($breakpoint) {\n @if type-of($breakpoint) == string {\n @media screen and (orientation: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A maximum-aspect-ratio media query breakpoint\n///\n@mixin break-at-ratio($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (max-aspect-ratio: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A minimum-maximum media query device breakpoint\n///\n@mixin break-at-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n @if nth($breakpoint, 2) {\n $min: nth($breakpoint, 1);\n $max: nth($breakpoint, 2);\n\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A minimum media query device breakpoint\n///\n@mixin break-from-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $min: nth($breakpoint, 1);\n\n @media screen and (min-width: $min) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A maximum media query device breakpoint\n///\n@mixin break-to-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $max: nth($breakpoint, 2);\n\n @media screen and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n","//\n// Name: Material Shadows\n// Description: Mixins for Material Design Shadows.\n// Version: 3.0.1\n//\n// Author: Denis Malinochkin\n// Git: https://github.com/mrmlnc/material-shadows\n//\n// twitter: @mrmlnc\n//\n// ------------------------------------\n\n\n// Mixins\n// ------------------------------------\n\n@mixin z-depth-transition() {\n transition: box-shadow .28s cubic-bezier(.4, 0, .2, 1);\n}\n\n@mixin z-depth-focus() {\n box-shadow: 0 0 8px rgba(0, 0, 0, .18), 0 8px 16px rgba(0, 0, 0, .36);\n}\n\n@mixin z-depth-2dp() {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14),\n 0 1px 5px 0 rgba(0, 0, 0, .12),\n 0 3px 1px -2px rgba(0, 0, 0, .2);\n}\n\n@mixin z-depth-3dp() {\n box-shadow: 0 3px 4px 0 rgba(0, 0, 0, .14),\n 0 1px 8px 0 rgba(0, 0, 0, .12),\n 0 3px 3px -2px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-4dp() {\n box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14),\n 0 1px 10px 0 rgba(0, 0, 0, .12),\n 0 2px 4px -1px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-6dp() {\n box-shadow: 0 6px 10px 0 rgba(0, 0, 0, .14),\n 0 1px 18px 0 rgba(0, 0, 0, .12),\n 0 3px 5px -1px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-8dp() {\n box-shadow: 0 8px 10px 1px rgba(0, 0, 0, .14),\n 0 3px 14px 2px rgba(0, 0, 0, .12),\n 0 5px 5px -3px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-16dp() {\n box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14),\n 0 6px 30px 5px rgba(0, 0, 0, .12),\n 0 8px 10px -5px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-24dp() {\n box-shadow: 0 9px 46px 8px rgba(0, 0, 0, .14),\n 0 24px 38px 3px rgba(0, 0, 0, .12),\n 0 11px 15px -7px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth($dp: 2) {\n @if $dp == 2 {\n @include z-depth-2dp();\n } @else if $dp == 3 {\n @include z-depth-3dp();\n } @else if $dp == 4 {\n @include z-depth-4dp();\n } @else if $dp == 6 {\n @include z-depth-6dp();\n } @else if $dp == 8 {\n @include z-depth-8dp();\n } @else if $dp == 16 {\n @include z-depth-16dp();\n } @else if $dp == 24 {\n @include z-depth-24dp();\n }\n}\n\n\n// Class generator\n// ------------------------------------\n\n@mixin z-depth-classes($transition: false, $focus: false) {\n @if $transition == true {\n &-transition {\n @include z-depth-transition();\n }\n }\n\n @if $focus == true {\n &-focus {\n @include z-depth-focus();\n }\n }\n\n // The available values for the shadow depth\n @each $depth in 2, 3, 4, 6, 8, 16, 24 {\n &-#{$depth}dp {\n @include z-depth($depth);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: base grid and containers\n// ----------------------------------------------------------------------------\n\n// Stretch container to viewport and set base `font-size`\nhtml {\n height: 100%;\n overflow-x: hidden;\n // Hack: normally, we would set the base `font-size` to `62.5%`, so we can\n // base all calculations on `10px`, but Chromium and Chrome define a minimal\n // `font-size` of `12px` if the system language is set to Chinese. For this\n // reason we just double the `font-size` and set it to `20px`.\n //\n // See https://github.com/squidfunk/mkdocs-material/issues/911\n font-size: 125%;\n\n // [screen medium +]: Set base `font-size` to `11px`\n @include break-from-device(screen medium) {\n font-size: 137.5%;\n }\n\n // [screen large +]: Set base `font-size` to `12px`\n @include break-from-device(screen large) {\n font-size: 150%;\n }\n}\n\n// Stretch body to container - flexbox is used, so the footer will always be\n// aligned to the bottom of the viewport\nbody {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100%;\n // Hack: reset `font-size` to `10px`, so the spacing for all inline elements\n // is correct again. Otherwise the spacing would be based on `20px`.\n font-size: px2rem(10px);\n background-color: var(--md-default-bg-color);\n\n // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m)\n @media print {\n display: block;\n }\n\n // Body in locked state\n &[data-md-state=\"lock\"] {\n\n // [tablet portrait -]: Omit scroll bubbling\n @include break-to-device(tablet portrait) {\n position: fixed;\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Grid container - this class is applied to wrapper elements within the\n// header, content area and footer, and makes sure that their width is limited\n// to `1220px`, and they are rendered centered if the screen is larger.\n.md-grid {\n max-width: px2rem(1220px);\n margin-right: auto;\n margin-left: auto;\n}\n\n// Main container\n.md-container {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n\n // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m)\n @media print {\n display: block;\n }\n}\n\n// Main area - stretch to remaining space of container\n.md-main {\n flex-grow: 1;\n\n // Main area wrapper\n &__inner {\n display: flex;\n height: 100%;\n margin-top: px2rem(24px + 6px);\n }\n}\n\n// Add ellipsis in case of overflowing text\n.md-ellipsis {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n// ----------------------------------------------------------------------------\n// Rules: navigational elements\n// ----------------------------------------------------------------------------\n\n// Toggle - this class is applied to checkbox elements, which are used to\n// implement the CSS-only drawer and navigation, as well as the search\n.md-toggle {\n display: none;\n}\n\n// Option - this class is applied to radio elements, which are used to\n// implement the color palette toggle\n.md-option {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n\n // Option label for checked radio button\n &:checked + label:not([hidden]) {\n display: block;\n }\n\n // Show outline for pointer devices\n &.focus-visible + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n }\n}\n\n// Skip link\n.md-skip {\n position: fixed;\n // Hack: if we don't set the negative `z-index`, the skip link will force the\n // creation of new layers when code blocks are near the header on scrolling\n z-index: -1;\n margin: px2rem(10px);\n padding: px2rem(6px) px2rem(10px);\n color: var(--md-default-bg-color);\n font-size: px2rem(12.8px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n outline-color: var(--md-accent-fg-color);\n transform: translateY(px2rem(8px));\n opacity: 0;\n\n // Show skip link on focus\n &:focus {\n z-index: 10;\n transform: translateY(0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 175ms 75ms;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: print styles\n// ----------------------------------------------------------------------------\n\n// Add margins to page\n@page {\n margin: 25mm;\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Announcement bar\n.md-announce {\n overflow: auto;\n background-color: var(--md-footer-bg-color);\n\n // [print]: Hide announcement bar\n @media print {\n display: none;\n }\n\n // Announcement wrapper\n &__inner {\n margin: px2rem(12px) auto;\n padding: 0 px2rem(16px);\n color: var(--md-footer-fg-color);\n font-size: px2rem(14px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-clipboard-icon: svg-load(\"material/content-copy.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Button to copy to clipboard\n.md-clipboard {\n position: absolute;\n top: px2em(8px);\n right: px2em(8px);\n z-index: 1;\n width: px2em(24px);\n height: px2em(24px);\n color: var(--md-default-fg-color--lightest);\n border-radius: px2rem(2px);\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(2px);\n cursor: pointer;\n transition: color 250ms;\n\n // [print]: Hide button\n @media print {\n display: none;\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Darken color on code block hover\n :hover > & {\n color: var(--md-default-fg-color--light);\n }\n\n // Button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Button icon - the width and height are defined in `em`, so the size is\n // automatically adjusted for nested code blocks (e.g. in admonitions)\n &::after {\n display: block;\n width: px2em(18px);\n height: px2em(18px);\n margin: 0 auto;\n background-color: currentColor;\n mask-image: var(--md-clipboard-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Inline button\n &--inline {\n cursor: pointer;\n\n // Code block\n code {\n transition:\n color 250ms,\n background-color 250ms;\n }\n\n // Code block on focus/hover\n &:focus code,\n &:hover code {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Content area\n.md-content {\n flex-grow: 1;\n // Hack: we must use `overflow: hidden`, so the content area is capped by\n // the dimensions of its parent. Otherwise, long code blocks might lead to\n // a wider content area which will break everything. This, however, induces\n // margin collapse, which will break scroll margins. Adding a large enough\n // scroll padding seems to do the trick, at least in Chrome and Firefox.\n overflow: hidden;\n scroll-padding-top: px2rem(1024px);\n\n // Content wrapper\n &__inner {\n margin: 0 px2rem(16px) px2rem(24px);\n padding-top: px2rem(12px);\n\n // [screen +]: Adjust spacing between content area and sidebars\n @include break-from-device(screen) {\n\n // Sidebar with navigation is visible\n .md-sidebar--primary:not([hidden]) ~ .md-content > & {\n margin-left: px2rem(24px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(24px);\n margin-left: px2rem(16px);\n }\n }\n\n // Sidebar with table of contents is visible\n .md-sidebar--secondary:not([hidden]) ~ .md-content > & {\n margin-right: px2rem(24px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(16px);\n margin-left: px2rem(24px);\n }\n }\n }\n\n // Hack: add pseudo element for spacing, as the overflow of the content\n // container may not be hidden due to an imminent offset error on targets\n &::before {\n display: block;\n height: px2rem(8px);\n content: \"\";\n }\n\n // Adjust spacing on last child\n > :last-child {\n margin-bottom: 0;\n }\n }\n\n // Button inside of the content area - these buttons are meant for actions on\n // a document-level, i.e. linking to related source code files, printing etc.\n &__button {\n float: right;\n margin: px2rem(8px) 0;\n margin-left: px2rem(8px);\n padding: 0;\n\n // [print]: Hide buttons\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n margin-right: px2rem(8px);\n margin-left: initial;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n\n // Adjust default link color for icons\n .md-typeset & {\n color: var(--md-default-fg-color--lighter);\n }\n\n // Align with body copy located next to icon\n svg {\n display: inline;\n vertical-align: top;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Dialog\n.md-dialog {\n @include z-depth(2);\n\n position: fixed;\n right: px2rem(16px);\n bottom: px2rem(16px);\n left: initial;\n z-index: 3;\n min-width: px2rem(222px);\n padding: px2rem(8px) px2rem(12px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n transform: translateY(100%);\n opacity: 0;\n transition:\n transform 0ms 400ms,\n opacity 400ms;\n pointer-events: none;\n\n // [print]: Hide dialog\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(16px);\n }\n\n // Dialog in open state\n &[data-md-state=\"open\"] {\n transform: translateY(0);\n opacity: 1;\n transition:\n transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1),\n opacity 400ms;\n pointer-events: initial;\n }\n\n // Dialog wrapper\n &__inner {\n color: var(--md-default-bg-color);\n font-size: px2rem(14px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Form button\n .md-button {\n display: inline-block;\n padding: px2em(10px) px2em(32px);\n color: var(--md-primary-fg-color);\n font-weight: 700;\n border: px2rem(2px) solid currentColor;\n border-radius: px2rem(2px);\n cursor: pointer;\n transition:\n color 125ms,\n background-color 125ms,\n border-color 125ms;\n\n // Primary button\n &--primary {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n border-color: var(--md-primary-fg-color);\n }\n\n // Button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n }\n }\n\n // Form input\n .md-input {\n height: px2rem(36px);\n padding: 0 px2rem(12px);\n font-size: px2rem(16px);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.1);\n transition: box-shadow 250ms;\n\n // Input on focus/hover\n &:focus,\n &:hover {\n box-shadow:\n 0 px2rem(8px) px2rem(20px) hsla(0, 0%, 0%, 0.15),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.15);\n }\n\n // Stretch to full width\n &--stretch {\n width: 100%;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Header - by default, the header will be sticky and stay always on top of the\n// viewport. If this behavior is not desired, just set `position: static`.\n.md-header {\n position: sticky;\n top: 0;\n right: 0;\n left: 0;\n z-index: 3;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n // Hack: reduce jitter by adding a transparent box shadow of the same size\n // so the size of the layer doesn't change during animation\n box-shadow:\n 0 0 px2rem(4px) rgba(0, 0, 0, 0),\n 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0);\n\n // [print]: Hide header\n @media print {\n display: none;\n }\n\n // Header in shadow state, i.e. shadow is visible\n &[data-md-state=\"shadow\"] {\n box-shadow:\n 0 0 px2rem(4px) rgba(0, 0, 0, 0.1),\n 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2);\n transition:\n transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),\n box-shadow 250ms;\n }\n\n // Header in hidden state, i.e. moved out of sight\n &[data-md-state=\"hidden\"] {\n transform: translateY(-100%);\n transition:\n transform 250ms cubic-bezier(0.8, 0, 0.6, 1),\n box-shadow 250ms;\n }\n\n // Header wrapper\n &__inner {\n display: flex;\n align-items: center;\n padding: 0 px2rem(4px);\n }\n\n // Header button\n &__button {\n position: relative;\n z-index: 1;\n margin: px2rem(4px);\n padding: px2rem(8px);\n color: currentColor;\n vertical-align: middle;\n outline-color: var(--md-accent-fg-color);\n cursor: pointer;\n transition: opacity 250ms;\n\n // Button on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Header button is visible\n &:not([hidden]) {\n display: inline-block;\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Button with logo, pointing to `config.site_url`\n &.md-logo {\n margin: px2rem(4px);\n padding: px2rem(8px);\n\n // [tablet -]: Hide button\n @include break-to-device(tablet) {\n display: none;\n }\n\n // Image or icon\n img,\n svg {\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n fill: currentColor;\n }\n }\n\n // Button for search\n &[for=\"__search\"] {\n\n // [tablet landscape +]: Hide button\n @include break-from-device(tablet landscape) {\n display: none;\n }\n\n // [no-js]: Hide button\n .no-js & {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n\n // Button for drawer\n &[for=\"__drawer\"] {\n\n // [screen +]: Hide button\n @include break-from-device(screen) {\n display: none;\n }\n }\n }\n\n // Header topic\n &__topic {\n position: absolute;\n display: flex;\n max-width: 100%;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n\n // Second header topic - title of the current page\n & + & {\n z-index: -1;\n transform: translateX(px2rem(25px));\n opacity: 0;\n transition:\n transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),\n opacity 150ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-25px));\n }\n }\n }\n\n // Header title\n &__title {\n flex-grow: 1;\n height: px2rem(48px);\n margin-right: px2rem(8px);\n margin-left: px2rem(20px);\n font-size: px2rem(18px);\n line-height: px2rem(48px);\n\n // Header title in active state, i.e. page title is visible\n &[data-md-state=\"active\"] .md-header__topic {\n z-index: -1;\n transform: translateX(px2rem(-25px));\n opacity: 0;\n transition:\n transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),\n opacity 150ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(25px));\n }\n\n // Second header topic - title of the current page\n + .md-header__topic {\n z-index: 0;\n transform: translateX(0);\n opacity: 1;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n pointer-events: initial;\n }\n }\n\n // Add ellipsis in case of overflowing text\n > .md-header__ellipsis {\n position: relative;\n width: 100%;\n height: 100%;\n }\n }\n\n // Header option\n &__option {\n display: flex;\n flex-shrink: 0;\n max-width: 100%;\n white-space: nowrap;\n transition:\n max-width 0ms 250ms,\n opacity 250ms 250ms;\n\n // Hide toggle when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n max-width: 0;\n opacity: 0;\n transition:\n max-width 0ms,\n opacity 0ms;\n }\n }\n\n // Repository information container\n &__source {\n display: none;\n\n // [tablet landscape +]: Show repository information\n @include break-from-device(tablet landscape) {\n display: block;\n width: px2rem(234px);\n max-width: px2rem(234px);\n margin-left: px2rem(20px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(20px);\n margin-left: initial;\n }\n }\n\n // [screen +]: Adjust spacing of search bar\n @include break-from-device(screen) {\n margin-left: px2rem(28px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(28px);\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Footer\n.md-footer {\n color: var(--md-footer-fg-color);\n background-color: var(--md-footer-bg-color);\n\n // [print]: Hide footer\n @media print {\n display: none;\n }\n\n // Footer wrapper\n &__inner {\n padding: px2rem(4px);\n overflow: auto;\n }\n\n // Footer link to previous and next page\n &__link {\n display: flex;\n padding-top: px2rem(28px);\n padding-bottom: px2rem(8px);\n outline-color: var(--md-accent-fg-color);\n transition: opacity 250ms;\n\n // [tablet +]: Adjust width to 50/50\n @include break-from-device(tablet) {\n width: 50%;\n }\n\n // Footer link on focus/hover\n &:focus,\n &:hover {\n opacity: 0.7;\n }\n\n // Footer link to previous page\n &--prev {\n float: left;\n\n // [mobile -]: Adjust width to 25/75 and hide title\n @include break-to-device(mobile) {\n width: 25%;\n\n // Hide footer title\n .md-footer__title {\n display: none;\n }\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: right;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n\n // Footer link to next page\n &--next {\n float: right;\n text-align: right;\n\n // [mobile -]: Adjust width to 25/75\n @include break-to-device(mobile) {\n width: 75%;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n text-align: left;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n }\n\n // Footer title\n &__title {\n position: relative;\n flex-grow: 1;\n max-width: calc(100% - #{px2rem(48px)});\n padding: 0 px2rem(20px);\n font-size: px2rem(18px);\n line-height: px2rem(48px);\n }\n\n // Footer link button\n &__button {\n margin: px2rem(4px);\n padding: px2rem(8px);\n }\n\n // Footer link direction (i.e. prev and next)\n &__direction {\n position: absolute;\n right: 0;\n left: 0;\n margin-top: px2rem(-20px);\n padding: 0 px2rem(20px);\n font-size: px2rem(12.8px);\n opacity: 0.7;\n }\n}\n\n// Footer metadata\n.md-footer-meta {\n background-color: var(--md-footer-bg-color--dark);\n\n // Footer metadata wrapper\n &__inner {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n padding: px2rem(4px);\n }\n\n // Lighten color for non-hovered text links\n html &.md-typeset a {\n color: var(--md-footer-fg-color--light);\n\n // Text link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-footer-fg-color);\n }\n }\n}\n\n// Footer copyright and theme information\n.md-footer-copyright {\n width: 100%;\n margin: auto px2rem(12px);\n padding: px2rem(8px) 0;\n color: var(--md-footer-fg-color--lighter);\n font-size: px2rem(12.8px);\n\n // [tablet portrait +]: Show copyright and social links in one line\n @include break-from-device(tablet portrait) {\n width: auto;\n }\n\n // Footer copyright highlight - this is the upper part of the copyright and\n // theme information, which will include a darker color than the theme link\n &__highlight {\n color: var(--md-footer-fg-color--light);\n }\n}\n\n// Footer social links\n.md-footer-social {\n margin: 0 px2rem(8px);\n padding: px2rem(4px) 0 px2rem(12px);\n\n // [tablet portrait +]: Show copyright and social links in one line\n @include break-from-device(tablet portrait) {\n padding: px2rem(12px) 0;\n }\n\n // Footer social link\n &__link {\n display: inline-block;\n width: px2rem(32px);\n height: px2rem(32px);\n text-align: center;\n\n // Adjust line-height to match height for correct alignment\n &::before {\n line-height: 1.9;\n }\n\n // Fill icon with current color\n svg {\n max-height: px2rem(16px);\n vertical-align: -25%;\n fill: currentColor;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-nav-icon--prev: svg-load(\"material/arrow-left.svg\");\n --md-nav-icon--next: svg-load(\"material/chevron-right.svg\");\n --md-toc-icon: svg-load(\"material/table-of-contents.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Navigation\n.md-nav {\n font-size: px2rem(14px);\n line-height: 1.3;\n\n // Navigation title\n &__title {\n display: block;\n padding: 0 px2rem(12px);\n overflow: hidden;\n font-weight: 700;\n text-overflow: ellipsis;\n\n // Navigaton button\n .md-nav__button {\n display: none;\n\n // Stretch images based on height, as it's the smaller dimension\n img {\n width: auto;\n height: 100%;\n }\n\n // Button with logo, pointing to `config.site_url`\n &.md-logo {\n\n // Image or icon\n img,\n svg {\n display: block;\n width: px2rem(48px);\n height: px2rem(48px);\n fill: currentColor;\n }\n }\n }\n }\n\n // Navigation list\n &__list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n // Navigation item\n &__item {\n padding: 0 px2rem(12px);\n\n // Navigation item on level 2\n & & {\n padding-right: 0;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: 0;\n }\n }\n }\n\n // Navigation link\n &__link {\n display: block;\n margin-top: 0.625em;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n transition: color 125ms;\n scroll-snap-align: start;\n\n // Link in blurred state\n &[data-md-state=\"blur\"] {\n color: var(--md-default-fg-color--light);\n }\n\n // Active link\n .md-nav__item &--active {\n color: var(--md-typeset-a-color);\n }\n\n // Navigation link in nested list\n .md-nav__item--nested > & {\n color: inherit;\n }\n\n // Navigation link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Navigation link on keyboard focus\n &.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n }\n\n // Navigation link to table of contents\n .md-nav--primary &[for=\"__toc\"] {\n display: none;\n\n // Table of contents icon\n .md-icon::after {\n display: block;\n width: 100%;\n height: 100%;\n mask-image: var(--md-toc-icon);\n background-color: currentColor;\n }\n\n // Hide table of contents\n ~ .md-nav {\n display: none;\n }\n }\n }\n\n // Repository information container\n &__source {\n display: none;\n }\n\n // [tablet -]: Layered navigation\n @include break-to-device(tablet) {\n\n // Primary and nested navigation\n &--primary,\n &--primary & {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--md-default-bg-color);\n }\n\n // Primary navigation\n &--primary {\n\n // Navigation title and item\n .md-nav__title,\n .md-nav__item {\n font-size: px2rem(16px);\n line-height: 1.5;\n }\n\n // Navigation title\n .md-nav__title {\n position: relative;\n height: px2rem(112px);\n padding: px2rem(60px) px2rem(16px) px2rem(4px);\n color: var(--md-default-fg-color--light);\n font-weight: 400;\n line-height: px2rem(48px);\n white-space: nowrap;\n background-color: var(--md-default-fg-color--lightest);\n cursor: pointer;\n\n // Navigation icon\n .md-nav__icon {\n position: absolute;\n top: px2rem(8px);\n left: px2rem(8px);\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n margin: px2rem(4px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(8px);\n left: initial;\n }\n\n // Navigation icon in link to previous level\n &::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--prev);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n }\n\n // Navigation list\n ~ .md-nav__list {\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n box-shadow:\n 0 px2rem(1px) 0 var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: y mandatory;\n touch-action: pan-y;\n\n // Omit border on first child\n > :first-child {\n border-top: 0;\n }\n }\n\n // Top-level navigation title\n &[for=\"__drawer\"] {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n }\n\n // Button with logo, pointing to `config.site_url`\n .md-logo {\n position: absolute;\n top: px2rem(4px);\n left: px2rem(4px);\n display: block;\n margin: px2rem(4px);\n padding: px2rem(8px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(4px);\n left: initial;\n }\n }\n }\n\n // Navigation list\n .md-nav__list {\n flex: 1;\n }\n\n // Navigation item\n .md-nav__item {\n padding: 0;\n border-top: px2rem(1px) solid var(--md-default-fg-color--lightest);\n\n // Navigation link in nested navigation\n &--nested > .md-nav__link {\n padding-right: px2rem(48px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(16px);\n padding-left: px2rem(48px);\n }\n }\n\n // Navigation link in active navigation\n &--active > .md-nav__link {\n color: var(--md-typeset-a-color);\n\n // Navigation link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n }\n }\n\n // Navigation link\n .md-nav__link {\n position: relative;\n margin-top: 0;\n padding: px2rem(12px) px2rem(16px);\n\n // Navigation icon\n .md-nav__icon {\n position: absolute;\n top: 50%;\n right: px2rem(12px);\n width: px2rem(24px);\n height: px2rem(24px);\n margin-top: px2rem(-12px);\n color: inherit;\n font-size: px2rem(24px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(12px);\n }\n\n // Navigation icon in link to next level\n &::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n }\n }\n\n // Flip icon vertically\n .md-nav__icon {\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] &::after {\n transform: scale(-1);\n }\n }\n\n // Table of contents contained in primary navigation\n .md-nav--secondary {\n\n // Navigation link - omit unnecessary layering\n .md-nav__link {\n position: static;\n }\n\n // Navigation on level 2-6\n .md-nav {\n position: static;\n background-color: transparent;\n\n // Navigation link on level 3\n .md-nav__link {\n padding-left: px2rem(28px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(28px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 4\n .md-nav .md-nav__link {\n padding-left: px2rem(40px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(40px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 5\n .md-nav .md-nav .md-nav__link {\n padding-left: px2rem(52px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(52px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 6\n .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: px2rem(64px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(64px);\n padding-left: initial;\n }\n }\n }\n }\n }\n\n // Table of contents\n &--secondary {\n background-color: transparent;\n }\n\n // Toggle for nested navigation\n &__toggle ~ & {\n display: flex;\n transform: translateX(100%);\n opacity: 0;\n transition:\n transform 250ms cubic-bezier(0.8, 0, 0.6, 1),\n opacity 125ms 50ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(-100%);\n }\n }\n\n // Show nested navigation when toggle is active\n &__toggle:checked ~ & {\n transform: translateX(0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 125ms 125ms;\n\n // Navigation list\n > .md-nav__list {\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n }\n }\n }\n\n // [tablet portrait -]: Layered navigation with table of contents\n @include break-to-device(tablet portrait) {\n\n // Show link to table of contents\n &--primary &__link[for=\"__toc\"] {\n display: block;\n padding-right: px2rem(48px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(16px);\n padding-left: px2rem(48px);\n }\n\n // Show table of contents icon\n .md-icon::after {\n content: \"\";\n }\n\n // Hide navigation link to current page\n + .md-nav__link {\n display: none;\n }\n\n // Show table of contents\n ~ .md-nav {\n display: flex;\n }\n }\n\n // Repository information container\n &__source {\n display: block;\n padding: 0 px2rem(4px);\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color--dark);\n }\n }\n\n // [tablet landscape]: Layered navigation with table of contents\n @include break-at-device(tablet landscape) {\n\n // Show link to integrated table of contents\n &--integrated &__link[for=\"__toc\"] {\n display: block;\n padding-right: px2rem(48px);\n scroll-snap-align: initial;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(16px);\n padding-left: px2rem(48px);\n }\n\n // Show table of contents icon\n .md-icon::after {\n content: \"\";\n }\n\n // Hide navigation link to current page\n + .md-nav__link {\n display: none;\n }\n\n // Show table of contents\n ~ .md-nav {\n display: flex;\n }\n }\n }\n\n // [tablet landscape +]: Tree-like table of contents\n @include break-from-device(tablet landscape) {\n\n // Navigation title\n &--secondary &__title {\n\n // Adjust snapping behavior\n &[for=\"__toc\"] {\n scroll-snap-align: start;\n }\n\n // Hide navigation icon\n .md-nav__icon {\n display: none;\n }\n }\n }\n\n // [screen +]: Tree-like navigation\n @include break-from-device(screen) {\n transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1);\n\n // Navigation title\n &--primary &__title {\n\n // Adjust snapping behavior\n &[for=\"__drawer\"] {\n scroll-snap-align: start;\n }\n\n // Hide navigation icon\n .md-nav__icon {\n display: none;\n }\n }\n\n // Hide toggle for nested navigation\n &__toggle ~ & {\n display: none;\n }\n\n // Show nested navigation when toggle is active or indeterminate\n &__toggle:checked ~ &,\n &__toggle:indeterminate ~ & {\n display: block;\n }\n\n // Hide navigation title in nested navigation\n &__item--nested > & > &__title {\n display: none;\n }\n\n // Navigation section\n &__item--section {\n display: block;\n margin: 1.25em 0;\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n\n // Hide navigation link, as sections are always expanded\n > .md-nav__link {\n display: none;\n }\n\n // Navigation\n > .md-nav {\n display: block;\n\n // Navigation title\n > .md-nav__title {\n display: block;\n padding: 0;\n pointer-events: none;\n scroll-snap-align: start;\n }\n\n // Adjust spacing on next level item\n > .md-nav__list > .md-nav__item {\n padding: 0;\n }\n }\n }\n\n // Navigation icon\n &__icon {\n float: right;\n width: px2rem(18px);\n height: px2rem(18px);\n transition: transform 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n transform: rotate(180deg);\n }\n\n // Navigation icon content\n &::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n vertical-align: px2rem(-2px);\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Navigation icon - rotate icon when toggle is active or indeterminate\n .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &,\n .md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link & {\n transform: rotate(90deg);\n }\n }\n\n // Modifier for when navigation tabs are rendered\n &--lifted {\n\n // Hide nested level 0 items and site title\n > .md-nav__list > .md-nav__item--nested,\n > .md-nav__title {\n display: none;\n }\n\n // Hide level 0 items\n > .md-nav__list > .md-nav__item {\n display: none;\n\n // Active parent navigation item\n &--active {\n display: block;\n padding: 0;\n\n // Hide nested links\n > .md-nav__link {\n display: none;\n }\n\n // Show title and adjust spacing\n > .md-nav > .md-nav__title {\n display: block;\n padding: 0 px2rem(12px);\n pointer-events: none;\n scroll-snap-align: start;\n }\n }\n }\n\n // Hack: Always show active navigation tab on breakpoint screen, despite\n // of checkbox being checked or not. Fixes #1655.\n .md-nav[data-md-level=\"1\"] {\n display: block;\n\n // Adjust spacing for level 1 items\n > .md-nav__list > .md-nav__item {\n padding-right: px2rem(12px);\n }\n }\n }\n\n // Modifier for when table of contents is rendered in primary navigation\n &--integrated &__link[for=\"__toc\"] ~ .md-nav {\n display: block;\n margin-bottom: 1.25em;\n border-left: px2rem(1px) solid var(--md-primary-fg-color);\n\n // Hide navigation title\n > .md-nav__title {\n display: none;\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-search-result-icon: svg-load(\"material/file-search-outline.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Search\n.md-search {\n position: relative;\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding: px2rem(4px) 0;\n }\n\n // [no-js]: Hide search\n .no-js & {\n display: none;\n }\n\n // Search overlay\n &__overlay {\n z-index: 1;\n opacity: 0;\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n position: absolute;\n top: px2rem(-20px);\n left: px2rem(-44px);\n width: px2rem(40px);\n height: px2rem(40px);\n overflow: hidden;\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(20px);\n transform-origin: center;\n transition:\n transform 300ms 100ms,\n opacity 200ms 200ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(-44px);\n left: initial;\n }\n\n // Show overlay when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n opacity: 1;\n transition:\n transform 400ms,\n opacity 100ms;\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n background-color: hsla(0, 0%, 0%, 0.54);\n cursor: pointer;\n transition:\n width 0ms 250ms,\n height 0ms 250ms,\n opacity 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n }\n\n // Show overlay when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n width: 100%;\n // Hack: when the header is translated upon scrolling, a new layer is\n // induced, which means that the height will now refer to the height of\n // the header, albeit positioning is fixed. This should be mitigated\n // in all cases when setting the height to 2x the viewport.\n height: 200vh;\n opacity: 1;\n transition:\n width 0ms,\n height 0ms,\n opacity 250ms;\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n\n // [mobile portrait -]: Scale up 45 times\n @include break-to-device(mobile portrait) {\n transform: scale(45);\n }\n\n // [mobile landscape]: Scale up 60 times\n @include break-at-device(mobile landscape) {\n transform: scale(60);\n }\n\n // [tablet portrait]: Scale up 75 times\n @include break-at-device(tablet portrait) {\n transform: scale(75);\n }\n }\n }\n\n // Search wrapper\n &__inner {\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n position: fixed;\n top: 0;\n left: 100%;\n z-index: 2;\n width: 100%;\n height: 100%;\n transform: translateX(5%);\n opacity: 0;\n transition:\n right 0ms 300ms,\n left 0ms 300ms,\n transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 150ms 150ms;\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n left: 0;\n transform: translateX(0);\n opacity: 1;\n transition:\n right 0ms 0ms,\n left 0ms 0ms,\n transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms 150ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n }\n }\n\n // Adjust for right-to-left languages\n html [dir=\"rtl\"] & {\n right: 100%;\n left: initial;\n transform: translateX(-5%);\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n position: relative;\n float: right;\n width: px2rem(234px);\n padding: px2rem(2px) 0;\n transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n\n // [tablet landscape]: Omit overlaying header title\n @include break-at-device(tablet landscape) {\n width: px2rem(468px);\n }\n\n // [screen +]: Match width of content area\n @include break-from-device(screen) {\n width: px2rem(688px);\n }\n }\n }\n\n // Search form\n &__form {\n position: relative;\n z-index: 2;\n height: px2rem(48px);\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0 px2rem(12px) transparent;\n transition:\n color 250ms,\n background-color 250ms;\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n height: px2rem(36px);\n background-color: hsla(0, 0%, 0%, 0.26);\n border-radius: px2rem(2px);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 100%, 0.12);\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px) px2rem(2px) 0 0;\n box-shadow: 0 0 px2rem(12px) hsla(0, 0%, 0%, 0.07);\n }\n }\n\n // Search input\n &__input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: 100%;\n padding: 0 px2rem(44px) 0 px2rem(72px);\n font-size: px2rem(18px);\n text-overflow: ellipsis;\n background: transparent;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: 0 px2rem(72px) 0 px2rem(44px);\n }\n\n // Search placeholder\n &::placeholder {\n transition: color 250ms;\n }\n\n // Search icon and placeholder\n ~ .md-search__icon,\n &::placeholder {\n color: var(--md-default-fg-color--light);\n }\n\n // Remove the \"x\" rendered by Internet Explorer\n &::-ms-clear {\n display: none;\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n width: 100%;\n height: px2rem(48px);\n font-size: px2rem(18px);\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n color: inherit;\n font-size: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n }\n\n // Search placeholder\n &::placeholder {\n color: var(--md-primary-bg-color--light);\n }\n\n // Search icon\n + .md-search__icon {\n color: var(--md-primary-bg-color);\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n text-overflow: clip;\n\n // Search icon and placeholder\n + .md-search__icon,\n &::placeholder {\n color: var(--md-default-fg-color--light);\n }\n }\n }\n }\n\n // Search icon\n &__icon {\n display: inline-block;\n width: px2rem(24px);\n height: px2rem(24px);\n cursor: pointer;\n transition:\n color 250ms,\n opacity 250ms;\n\n // Search icon on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Search focus button\n &[for=\"__search\"] {\n position: absolute;\n top: px2rem(6px);\n left: px2rem(10px);\n z-index: 2;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(10px);\n left: initial;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(12px);\n left: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(16px);\n left: initial;\n }\n\n // Hide the magnifying glass\n svg:first-child {\n display: none;\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n pointer-events: none;\n\n // Hide the back arrow\n svg:last-child {\n display: none;\n }\n }\n }\n }\n\n // Search options\n &__options {\n position: absolute;\n top: px2rem(6px);\n right: px2rem(10px);\n z-index: 2;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(10px);\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(12px);\n right: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(16px);\n }\n }\n\n // Search option buttons\n > * {\n margin-left: px2rem(4px);\n color: var(--md-default-fg-color--light);\n transform: scale(0.75);\n opacity: 0;\n transition:\n transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Show reset button when search is active and input non-empty\n [data-md-toggle=\"search\"]:checked ~ .md-header\n .md-search__input:valid ~ & {\n transform: scale(1);\n opacity: 1;\n pointer-events: initial;\n\n // Search focus icon\n &:hover {\n opacity: 0.7;\n }\n }\n }\n }\n\n // Search suggestions\n &__suggest {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n padding: 0 px2rem(44px) 0 px2rem(72px);\n color: var(--md-default-fg-color--lighter);\n font-size: px2rem(18px);\n white-space: nowrap;\n opacity: 0;\n transition: opacity 50ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: 0 px2rem(72px) 0 px2rem(44px);\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n font-size: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n }\n }\n\n // Show suggestions when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n opacity: 1;\n transition: opacity 300ms 100ms;\n }\n }\n\n // Search output\n &__output {\n position: absolute;\n z-index: 1;\n width: 100%;\n overflow: hidden;\n border-radius: 0 0 px2rem(2px) px2rem(2px);\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(48px);\n bottom: 0;\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n top: px2rem(38px);\n opacity: 0;\n transition: opacity 400ms;\n\n // Show output when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n @include z-depth(6);\n\n opacity: 1;\n }\n }\n }\n\n // Search scroll wrapper\n &__scrollwrap {\n height: 100%;\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n // Hack: Chrome 88+ has weird overscroll behavior. Overall, scroll snapping\n // seems to be something that is not ready for prime time on some browsers.\n // scroll-snap-type: y mandatory;\n touch-action: pan-y;\n\n // Mitigiate excessive repaints on non-retina devices\n @media (max-resolution: 1dppx) {\n transform: translateZ(0);\n }\n\n // [tablet landscape]: Set fixed width to omit unnecessary reflow\n @include break-at-device(tablet landscape) {\n width: px2rem(468px);\n }\n\n // [screen +]: Set fixed width to omit unnecessary reflow\n @include break-from-device(screen) {\n width: px2rem(688px);\n }\n\n // [tablet landscape +]: Limit height to viewport\n @include break-from-device(tablet landscape) {\n max-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Show scroll wrapper when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n max-height: 75vh;\n }\n\n // Search scroll wrapper on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n }\n}\n\n// Search result\n.md-search-result {\n color: var(--md-default-fg-color);\n word-break: break-word;\n\n // Search result metadata\n &__meta {\n padding: 0 px2rem(16px);\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n line-height: px2rem(36px);\n background-color: var(--md-default-fg-color--lightest);\n scroll-snap-align: start;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: initial;\n }\n }\n }\n\n // Search result list\n &__list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n // Search result item\n &__item {\n box-shadow: 0 px2rem(-1px) 0 var(--md-default-fg-color--lightest);\n\n // Omit border on first child\n &:first-child {\n box-shadow: none;\n }\n }\n\n // Search result link\n &__link {\n display: block;\n outline: none;\n transition: background-color 250ms;\n scroll-snap-align: start;\n\n // Search result link on focus/hover\n &:focus,\n &:hover {\n background-color: var(--md-accent-fg-color--transparent);\n }\n\n // Adjust spacing on last child of last link\n &:last-child p:last-child {\n margin-bottom: px2rem(12px);\n }\n }\n\n // Search result more link\n &__more summary {\n display: block;\n padding: px2em(12px) px2rem(16px);\n color: var(--md-typeset-a-color);\n font-size: px2rem(12.8px);\n outline: none;\n cursor: pointer;\n transition:\n color 250ms,\n background-color 250ms;\n scroll-snap-align: start;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: px2rem(16px);\n }\n }\n\n // Search result more link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n }\n\n // Hide native details marker\n &::marker,\n &::-webkit-details-marker {\n display: none;\n }\n\n // Adjust transparency of less relevant results\n ~ * > * {\n opacity: 0.65;\n }\n }\n\n // Search result article\n &__article {\n position: relative;\n padding: 0 px2rem(16px);\n overflow: hidden;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: px2rem(16px);\n }\n }\n\n // Search result article document\n &--document {\n\n // Search result title\n .md-search-result__title {\n margin: px2rem(11px) 0;\n font-weight: 400;\n font-size: px2rem(16px);\n line-height: 1.4;\n }\n }\n }\n\n // Search result icon\n &__icon {\n position: absolute;\n left: 0;\n width: px2rem(24px);\n height: px2rem(24px);\n margin: px2rem(10px);\n color: var(--md-default-fg-color--light);\n\n // [tablet portrait -]: Hide icon\n @include break-to-device(tablet portrait) {\n display: none;\n }\n\n // Search result icon content\n &::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-search-result-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n\n // Flip icon vertically\n &::after {\n transform: scaleX(-1);\n }\n }\n }\n\n // Search result title\n &__title {\n margin: 0.5em 0;\n font-weight: 700;\n font-size: px2rem(12.8px);\n line-height: 1.6;\n }\n\n // Search result teaser\n &__teaser {\n display: -webkit-box;\n max-height: px2rem(40px);\n margin: 0.5em 0;\n overflow: hidden;\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n line-height: 1.6;\n text-overflow: ellipsis;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n\n // [mobile -]: Adjust number of lines\n @include break-to-device(mobile) {\n max-height: px2rem(60px);\n -webkit-line-clamp: 3;\n }\n\n // [tablet landscape]: Adjust number of lines\n @include break-at-device(tablet landscape) {\n max-height: px2rem(60px);\n -webkit-line-clamp: 3;\n }\n\n // Search term highlighting\n mark {\n text-decoration: underline;\n background-color: transparent;\n }\n }\n\n // Search result terms\n &__terms {\n margin: 0.5em 0;\n font-size: px2rem(12.8px);\n font-style: italic;\n }\n\n // Search term highlighting\n mark {\n color: var(--md-accent-fg-color);\n background-color: transparent;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Selection\n.md-select {\n position: relative;\n z-index: 1;\n\n // Selection bubble\n &__inner {\n position: absolute;\n top: calc(100% - #{px2rem(4px)});\n left: 50%;\n max-height: 0;\n margin-top: px2rem(4px);\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n transform: translate3d(-50%, px2rem(6px), 0);\n opacity: 0;\n transition:\n transform 250ms 375ms,\n opacity 250ms 250ms,\n max-height 0ms 500ms;\n\n // Selection bubble on parent focus/hover\n .md-select:focus-within &,\n .md-select:hover & {\n max-height: px2rem(200px);\n transform: translate3d(-50%, 0, 0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 250ms,\n max-height 0ms;\n }\n\n // Selection bubble handle\n &::after {\n position: absolute;\n top: 0;\n left: 50%;\n width: 0;\n height: 0;\n margin-top: px2rem(-4px);\n margin-left: px2rem(-4px);\n border: px2rem(4px) solid transparent;\n border-top: 0;\n border-bottom-color: var(--md-default-bg-color);\n content: \"\";\n }\n }\n\n // Selection list\n &__list {\n max-height: inherit;\n margin: 0;\n padding: 0;\n overflow: auto;\n font-size: px2rem(16px);\n list-style-type: none;\n border-radius: px2rem(2px);\n }\n\n // Selection item\n &__item {\n line-height: px2rem(36px);\n }\n\n // Selection link\n &__link {\n display: block;\n width: 100%;\n padding-right: px2rem(24px);\n padding-left: px2rem(12px);\n outline: none;\n cursor: pointer;\n transition:\n background-color 250ms,\n color 250ms;\n scroll-snap-align: start;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: px2rem(24px);\n }\n\n // Link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Link on focus\n &:focus {\n background-color: var(--md-default-fg-color--lightest);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Sidebar\n.md-sidebar {\n position: sticky;\n top: px2rem(48px);\n flex-shrink: 0;\n align-self: flex-start;\n width: px2rem(242px);\n padding: px2rem(24px) 0;\n\n // [print]: Hide sidebar\n @media print {\n display: none;\n }\n\n // [tablet -]: Show navigation as drawer\n @include break-to-device(tablet) {\n\n // Primary sidebar with navigation\n &--primary {\n position: fixed;\n top: 0;\n left: px2rem(-242px);\n z-index: 4;\n display: block;\n width: px2rem(242px);\n height: 100%;\n background-color: var(--md-default-bg-color);\n transform: translateX(0);\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n box-shadow 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(-242px);\n left: initial;\n }\n\n // Show sidebar when drawer is active\n [data-md-toggle=\"drawer\"]:checked ~ .md-container & {\n @include z-depth(8);\n\n transform: translateX(px2rem(242px));\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-242px));\n }\n }\n\n // Stretch scroll wrapper for primary sidebar\n .md-sidebar__scrollwrap {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n margin: 0;\n scroll-snap-type: none;\n overflow: hidden;\n }\n }\n }\n\n // [screen +]: Show navigation as sidebar\n @include break-from-device(screen) {\n height: 0;\n\n // [no-js]: Switch to native sticky behavior\n .no-js & {\n height: auto;\n }\n }\n\n // Secondary sidebar with table of contents\n &--secondary {\n display: none;\n order: 2;\n\n // [tablet landscape +]: Show table of contents as sidebar\n @include break-from-device(tablet landscape) {\n height: 0;\n\n // [no-js]: Switch to native sticky behavior\n .no-js & {\n height: auto;\n }\n\n // Sidebar is visible\n &:not([hidden]) {\n display: block;\n }\n\n // Ensure smooth scrolling on iOS\n .md-sidebar__scrollwrap {\n touch-action: pan-y;\n }\n }\n }\n\n // Sidebar scroll wrapper\n &__scrollwrap {\n margin: 0 px2rem(4px);\n overflow-y: auto;\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n // Hack: Chrome 81+ exhibits a strange bug, where it scrolls the container\n // to the bottom if `scroll-snap-type` is set on the initial render. For\n // this reason, we disable scroll snapping until this is resolved (#1667).\n // scroll-snap-type: y mandatory;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Sidebar scroll wrapper on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n}\n\n// [tablet -]: Show overlay on active drawer\n@include break-to-device(tablet) {\n\n // Sidebar overlay\n .md-overlay {\n position: fixed;\n top: 0;\n z-index: 4;\n width: 0;\n height: 0;\n background-color: hsla(0, 0%, 0%, 0.54);\n opacity: 0;\n transition:\n width 0ms 250ms,\n height 0ms 250ms,\n opacity 250ms;\n\n // Show overlay when drawer is active\n [data-md-toggle=\"drawer\"]:checked ~ & {\n width: 100%;\n height: 100%;\n opacity: 1;\n transition:\n width 0ms,\n height 0ms,\n opacity 250ms;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Keyframes\n// ----------------------------------------------------------------------------\n\n// Show repository facts\n@keyframes facts {\n 0% {\n height: 0;\n }\n\n 100% {\n height: px2rem(13px);\n }\n}\n\n// Show repository fact\n@keyframes fact {\n 0% {\n transform: translateY(100%);\n opacity: 0;\n }\n\n 50% {\n opacity: 0;\n }\n\n 100% {\n transform: translateY(0%);\n opacity: 1;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-source-forks-icon: svg-load(\"octicons/repo-forked-16.svg\");\n --md-source-repositories-icon: svg-load(\"octicons/repo-16.svg\");\n --md-source-stars-icon: svg-load(\"octicons/star-16.svg\");\n --md-source-version-icon: svg-load(\"octicons/tag-16.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Repository information\n.md-source {\n display: block;\n font-size: px2rem(13px);\n line-height: 1.2;\n white-space: nowrap;\n outline-color: var(--md-accent-fg-color);\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n transition: opacity 250ms;\n\n // Repository information on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Repository icon\n &__icon {\n display: inline-block;\n width: px2rem(40px);\n height: px2rem(48px);\n vertical-align: middle;\n\n // Align with margin only (as opposed to normal button alignment)\n svg {\n margin-top: px2rem(12px);\n margin-left: px2rem(12px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(12px);\n margin-left: initial;\n }\n }\n\n // Adjust spacing if icon is present\n + .md-source__repository {\n margin-left: px2rem(-40px);\n padding-left: px2rem(40px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(-40px);\n margin-left: initial;\n padding-right: px2rem(40px);\n padding-left: initial;\n }\n }\n }\n\n // Repository name\n &__repository {\n display: inline-block;\n max-width: calc(100% - #{px2rem(24px)});\n margin-left: px2rem(12px);\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n }\n\n // Repository facts\n &__facts {\n margin: px2rem(2px) 0 0;\n padding: 0;\n overflow: hidden;\n font-size: px2rem(11px);\n list-style-type: none;\n opacity: 0.75;\n\n // Show after the data was loaded\n [data-md-state=\"done\"] & {\n animation: facts 250ms ease-in;\n }\n }\n\n // Repository fact\n &__fact {\n display: inline-block;\n\n // Show after the data was loaded\n [data-md-state=\"done\"] & {\n animation: fact 400ms ease-out;\n }\n\n // Repository fact icon\n &::before {\n display: inline-block;\n width: px2rem(12px);\n height: px2rem(12px);\n margin-right: px2rem(2px);\n vertical-align: text-top;\n background-color: currentColor;\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Adjust spacing for repository fact icon\n &:nth-child(1n+2)::before {\n margin-left: px2rem(8px);\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: initial;\n margin-left: px2rem(2px);\n\n // Adjust spacing for repository fact icon\n &:nth-child(1n+2)::before {\n margin-right: px2rem(8px);\n margin-left: initial;\n }\n }\n\n // Repository fact: version\n &--version::before {\n mask-image: var(--md-source-version-icon);\n }\n\n // Repository fact: stars\n &--stars::before {\n mask-image: var(--md-source-stars-icon);\n }\n\n // Repository fact: forks\n &--forks::before {\n mask-image: var(--md-source-forks-icon);\n }\n\n // Repository fact: repositories\n &--repositories::before {\n mask-image: var(--md-source-repositories-icon);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Navigation tabs\n.md-tabs {\n width: 100%;\n overflow: auto;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n\n // [print]: Hide tabs\n @media print {\n display: none;\n }\n\n // [tablet -]: Hide tabs\n @include break-to-device(tablet) {\n display: none;\n }\n\n // Tabs in hidden state, i.e. when scrolling down\n &[data-md-state=\"hidden\"] {\n pointer-events: none;\n }\n\n // Navigation tabs list\n &__list {\n margin: 0;\n margin-left: px2rem(4px);\n padding: 0;\n white-space: nowrap;\n list-style: none;\n contain: content;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(4px);\n margin-left: initial;\n }\n }\n\n // Navigation tabs item\n &__item {\n display: inline-block;\n height: px2rem(48px);\n padding-right: px2rem(12px);\n padding-left: px2rem(12px);\n }\n\n // Navigation tabs link - could be defined as block elements and aligned via\n // line height, but this would imply more repaints when scrolling\n &__link {\n display: block;\n margin-top: px2rem(16px);\n font-size: px2rem(14px);\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n // Hack: save a repaint when tabs are appearing on scrolling up\n backface-visibility: hidden;\n opacity: 0.7;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 250ms;\n\n // Active link and link on focus/hover\n &--active,\n &:focus,\n &:hover {\n color: inherit;\n opacity: 1;\n }\n\n // Delay transitions by a small amount\n @for $i from 2 through 16 {\n .md-tabs__item:nth-child(#{$i}) & {\n transition-delay: 20ms * ($i - 1);\n }\n }\n\n // Hide tabs upon scrolling - disable transition to minimizes repaints\n // while scrolling down, while scrolling up seems to be okay\n .md-tabs[data-md-state=\"hidden\"] & {\n transform: translateY(50%);\n opacity: 0;\n transition:\n transform 0ms 100ms,\n opacity 100ms;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Back-to-top button\n.md-top {\n position: fixed;\n top: px2rem(48px + 16px);\n z-index: 2;\n margin-left: 50%;\n padding: px2rem(8px) px2rem(16px);\n color: var(--md-default-fg-color--light);\n font-size: px2rem(14px);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(32px);\n outline: none;\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n transform: translate(-50%, 0);\n transition:\n color 125ms,\n background-color 125ms,\n transform 125ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 125ms;\n\n // [print]: Hide back-to-top button\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n }\n\n // Back-to-top button in hidden state\n &[data-md-state=\"hidden\"] {\n transform: translate(-50%, px2rem(4px));\n opacity: 0;\n transition-duration: 0ms;\n pointer-events: none;\n }\n\n // Back-to-top button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n }\n\n // Inline icon\n svg {\n display: inline-block;\n vertical-align: -0.5em;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Keyframes\n// ----------------------------------------------------------------------------\n\n// See https://github.com/squidfunk/mkdocs-material/issues/2429\n@keyframes hoverfix {\n 0% {\n pointer-events: none;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-version-icon: svg-load(\"fontawesome/solid/caret-down.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Version selection\n.md-version {\n flex-shrink: 0;\n height: px2rem(48px);\n font-size: px2rem(16px);\n\n // Current selection\n &__current {\n position: relative;\n // Hack: in general, we would use `vertical-align` to align the version at\n // the bottom with the title, but since the list uses absolute positioning,\n // this won't work consistently. Furthermore, we would need to use inline\n // positioning to align the links, which looks jagged.\n top: px2rem(1px);\n margin-right: px2rem(8px);\n margin-left: px2rem(28px);\n color: inherit;\n outline: none;\n cursor: pointer;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(28px);\n margin-left: px2rem(8px);\n }\n\n // Version selection icon\n &::after {\n display: inline-block;\n width: px2rem(8px);\n height: px2rem(12px);\n margin-left: px2rem(8px);\n background-color: currentColor;\n mask-image: var(--md-version-icon);\n mask-repeat: no-repeat;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(8px);\n margin-left: initial;\n }\n }\n }\n\n // Version selection list\n &__list {\n position: absolute;\n top: px2rem(3px);\n z-index: 1;\n max-height: 0;\n margin: px2rem(4px) px2rem(16px);\n padding: 0;\n overflow: auto;\n color: var(--md-default-fg-color);\n list-style-type: none;\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n opacity: 0;\n transition:\n max-height 0ms 500ms,\n opacity 250ms 250ms;\n scroll-snap-type: y mandatory;\n\n // Version selection list on parent focus/hover\n .md-version:focus-within &,\n .md-version:hover & {\n max-height: px2rem(200px);\n opacity: 1;\n transition:\n max-height 0ms,\n opacity 250ms;\n }\n\n // Fix hover on touch devices\n @media (pointer: coarse) {\n\n // Switch off on hover\n .md-version:hover & {\n animation: hoverfix 250ms forwards;\n }\n\n // Enable on focus\n .md-version:focus-within & {\n animation: none;\n }\n }\n }\n\n // Version selection item\n &__item {\n line-height: px2rem(36px);\n }\n\n // Version selection link\n &__link {\n display: block;\n width: 100%;\n padding-right: px2rem(24px);\n padding-left: px2rem(12px);\n white-space: nowrap;\n outline: none;\n cursor: pointer;\n transition:\n color 250ms,\n background-color 250ms;\n scroll-snap-align: start;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: px2rem(24px);\n }\n\n // Link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Link on focus\n &:focus {\n background-color: var(--md-default-fg-color--lightest);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n/// Admonition flavours\n$admonitions: (\n note: pencil $clr-blue-a200,\n abstract summary tldr: text-subject $clr-light-blue-a400,\n info todo: information $clr-cyan-a700,\n tip hint important: fire $clr-teal-a700,\n success check done: check-circle $clr-green-a700,\n question help faq: help-circle $clr-light-green-a700,\n warning caution attention: alert $clr-orange-a400,\n failure fail missing: close-circle $clr-red-a200,\n danger error: flash-circle $clr-red-a400,\n bug: bug $clr-pink-a400,\n example: format-list-numbered $clr-deep-purple-a200,\n quote cite: format-quote-close $clr-grey\n) !default;\n\n// ----------------------------------------------------------------------------\n// Rules: layout\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n @each $names, $props in $admonitions {\n --md-admonition-icon--#{nth($names, 1)}:\n svg-load(\"material/#{nth($props, 1)}.svg\");\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Admonition\n .admonition {\n margin: px2em(20px, 12.8px) 0;\n padding: 0 px2rem(12px);\n overflow: hidden;\n color: var(--md-admonition-fg-color);\n font-size: px2rem(12.8px);\n page-break-inside: avoid;\n background-color: var(--md-admonition-bg-color);\n border-left: px2rem(4px) solid $clr-blue-a200;\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.05),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.05);\n\n // [print]: Omit shadow as it may lead to rendering errors\n @media print {\n box-shadow: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n border-right: px2rem(4px) solid $clr-blue-a200;\n border-left: none;\n }\n\n // Adjust vertical spacing for nested admonitions\n .admonition {\n margin-top: 1em;\n margin-bottom: 1em;\n }\n\n // Adjust spacing for contained table wrappers\n .md-typeset__scrollwrap {\n margin: 1em px2rem(-12px);\n }\n\n // Adjust spacing for contained tables\n .md-typeset__table {\n padding: 0 px2rem(12px);\n }\n\n // Adjust spacing for single-child tabbed block container\n > .tabbed-set:only-child {\n margin-top: 0;\n }\n\n // Adjust spacing on last child\n html & > :last-child {\n margin-bottom: px2rem(12px);\n }\n }\n\n // Admonition title\n .admonition-title {\n position: relative;\n margin: 0 px2rem(-12px) 0 px2rem(-16px);\n padding: px2rem(8px) px2rem(12px) px2rem(8px) px2rem(40px);\n font-weight: 700;\n background-color: transparentize($clr-blue-a200, 0.9);\n border-left: px2rem(4px) solid $clr-blue-a200;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin: 0 px2rem(-16px) 0 px2rem(-12px);\n padding: px2rem(8px) px2rem(40px) px2rem(8px) px2rem(12px);\n border-right: px2rem(4px) solid $clr-blue-a200;\n border-left: none;\n }\n\n // Adjust spacing for title-only admonitions\n html &:last-child {\n margin-bottom: 0;\n }\n\n // Admonition icon\n &::before {\n position: absolute;\n left: px2rem(12px);\n width: px2rem(20px);\n height: px2rem(20px);\n background-color: $clr-blue-a200;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(12px);\n left: initial;\n }\n }\n\n // Adjust spacing on last tabbed block container child - if the tabbed\n // block container is the sole child, it looks better to omit the margin\n + .tabbed-set:last-child {\n margin-top: 0;\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: flavours\n// ----------------------------------------------------------------------------\n\n@each $names, $props in $admonitions {\n $name: nth($names, 1);\n $tint: nth($props, 2);\n\n // Admonition flavour\n .md-typeset .admonition.#{$name} {\n border-color: $tint;\n }\n\n // Admonition flavour title\n .md-typeset .#{$name} > .admonition-title {\n background-color: transparentize($tint, 0.9);\n border-color: $tint;\n\n // Admonition icon\n &::before {\n background-color: $tint;\n mask-image: var(--md-admonition-icon--#{$name});\n mask-repeat: no-repeat;\n mask-size: contain;\n }\n }\n\n // Define synonyms for flavours\n @if length($names) > 1 {\n @for $n from 2 through length($names) {\n .#{nth($names, $n)} {\n @extend .#{$name};\n }\n }\n }\n}\n","// ==========================================================================\n//\n// Name: UI Color Palette\n// Description: The color palette of material design.\n// Version: 2.3.1\n//\n// Author: Denis Malinochkin\n// Git: https://github.com/mrmlnc/material-color\n//\n// twitter: @mrmlnc\n//\n// ==========================================================================\n\n\n//\n// List of base colors\n//\n\n// $clr-red\n// $clr-pink\n// $clr-purple\n// $clr-deep-purple\n// $clr-indigo\n// $clr-blue\n// $clr-light-blue\n// $clr-cyan\n// $clr-teal\n// $clr-green\n// $clr-light-green\n// $clr-lime\n// $clr-yellow\n// $clr-amber\n// $clr-orange\n// $clr-deep-orange\n// $clr-brown\n// $clr-grey\n// $clr-blue-grey\n// $clr-black\n// $clr-white\n\n\n//\n// Red\n//\n\n$clr-red-list: (\n \"base\": #f44336,\n \"50\": #ffebee,\n \"100\": #ffcdd2,\n \"200\": #ef9a9a,\n \"300\": #e57373,\n \"400\": #ef5350,\n \"500\": #f44336,\n \"600\": #e53935,\n \"700\": #d32f2f,\n \"800\": #c62828,\n \"900\": #b71c1c,\n \"a100\": #ff8a80,\n \"a200\": #ff5252,\n \"a400\": #ff1744,\n \"a700\": #d50000\n);\n\n$clr-red: map-get($clr-red-list, \"base\");\n\n$clr-red-50: map-get($clr-red-list, \"50\");\n$clr-red-100: map-get($clr-red-list, \"100\");\n$clr-red-200: map-get($clr-red-list, \"200\");\n$clr-red-300: map-get($clr-red-list, \"300\");\n$clr-red-400: map-get($clr-red-list, \"400\");\n$clr-red-500: map-get($clr-red-list, \"500\");\n$clr-red-600: map-get($clr-red-list, \"600\");\n$clr-red-700: map-get($clr-red-list, \"700\");\n$clr-red-800: map-get($clr-red-list, \"800\");\n$clr-red-900: map-get($clr-red-list, \"900\");\n$clr-red-a100: map-get($clr-red-list, \"a100\");\n$clr-red-a200: map-get($clr-red-list, \"a200\");\n$clr-red-a400: map-get($clr-red-list, \"a400\");\n$clr-red-a700: map-get($clr-red-list, \"a700\");\n\n\n//\n// Pink\n//\n\n$clr-pink-list: (\n \"base\": #e91e63,\n \"50\": #fce4ec,\n \"100\": #f8bbd0,\n \"200\": #f48fb1,\n \"300\": #f06292,\n \"400\": #ec407a,\n \"500\": #e91e63,\n \"600\": #d81b60,\n \"700\": #c2185b,\n \"800\": #ad1457,\n \"900\": #880e4f,\n \"a100\": #ff80ab,\n \"a200\": #ff4081,\n \"a400\": #f50057,\n \"a700\": #c51162\n);\n\n$clr-pink: map-get($clr-pink-list, \"base\");\n\n$clr-pink-50: map-get($clr-pink-list, \"50\");\n$clr-pink-100: map-get($clr-pink-list, \"100\");\n$clr-pink-200: map-get($clr-pink-list, \"200\");\n$clr-pink-300: map-get($clr-pink-list, \"300\");\n$clr-pink-400: map-get($clr-pink-list, \"400\");\n$clr-pink-500: map-get($clr-pink-list, \"500\");\n$clr-pink-600: map-get($clr-pink-list, \"600\");\n$clr-pink-700: map-get($clr-pink-list, \"700\");\n$clr-pink-800: map-get($clr-pink-list, \"800\");\n$clr-pink-900: map-get($clr-pink-list, \"900\");\n$clr-pink-a100: map-get($clr-pink-list, \"a100\");\n$clr-pink-a200: map-get($clr-pink-list, \"a200\");\n$clr-pink-a400: map-get($clr-pink-list, \"a400\");\n$clr-pink-a700: map-get($clr-pink-list, \"a700\");\n\n\n//\n// Purple\n//\n\n$clr-purple-list: (\n \"base\": #9c27b0,\n \"50\": #f3e5f5,\n \"100\": #e1bee7,\n \"200\": #ce93d8,\n \"300\": #ba68c8,\n \"400\": #ab47bc,\n \"500\": #9c27b0,\n \"600\": #8e24aa,\n \"700\": #7b1fa2,\n \"800\": #6a1b9a,\n \"900\": #4a148c,\n \"a100\": #ea80fc,\n \"a200\": #e040fb,\n \"a400\": #d500f9,\n \"a700\": #aa00ff\n);\n\n$clr-purple: map-get($clr-purple-list, \"base\");\n\n$clr-purple-50: map-get($clr-purple-list, \"50\");\n$clr-purple-100: map-get($clr-purple-list, \"100\");\n$clr-purple-200: map-get($clr-purple-list, \"200\");\n$clr-purple-300: map-get($clr-purple-list, \"300\");\n$clr-purple-400: map-get($clr-purple-list, \"400\");\n$clr-purple-500: map-get($clr-purple-list, \"500\");\n$clr-purple-600: map-get($clr-purple-list, \"600\");\n$clr-purple-700: map-get($clr-purple-list, \"700\");\n$clr-purple-800: map-get($clr-purple-list, \"800\");\n$clr-purple-900: map-get($clr-purple-list, \"900\");\n$clr-purple-a100: map-get($clr-purple-list, \"a100\");\n$clr-purple-a200: map-get($clr-purple-list, \"a200\");\n$clr-purple-a400: map-get($clr-purple-list, \"a400\");\n$clr-purple-a700: map-get($clr-purple-list, \"a700\");\n\n\n//\n// Deep purple\n//\n\n$clr-deep-purple-list: (\n \"base\": #673ab7,\n \"50\": #ede7f6,\n \"100\": #d1c4e9,\n \"200\": #b39ddb,\n \"300\": #9575cd,\n \"400\": #7e57c2,\n \"500\": #673ab7,\n \"600\": #5e35b1,\n \"700\": #512da8,\n \"800\": #4527a0,\n \"900\": #311b92,\n \"a100\": #b388ff,\n \"a200\": #7c4dff,\n \"a400\": #651fff,\n \"a700\": #6200ea\n);\n\n$clr-deep-purple: map-get($clr-deep-purple-list, \"base\");\n\n$clr-deep-purple-50: map-get($clr-deep-purple-list, \"50\");\n$clr-deep-purple-100: map-get($clr-deep-purple-list, \"100\");\n$clr-deep-purple-200: map-get($clr-deep-purple-list, \"200\");\n$clr-deep-purple-300: map-get($clr-deep-purple-list, \"300\");\n$clr-deep-purple-400: map-get($clr-deep-purple-list, \"400\");\n$clr-deep-purple-500: map-get($clr-deep-purple-list, \"500\");\n$clr-deep-purple-600: map-get($clr-deep-purple-list, \"600\");\n$clr-deep-purple-700: map-get($clr-deep-purple-list, \"700\");\n$clr-deep-purple-800: map-get($clr-deep-purple-list, \"800\");\n$clr-deep-purple-900: map-get($clr-deep-purple-list, \"900\");\n$clr-deep-purple-a100: map-get($clr-deep-purple-list, \"a100\");\n$clr-deep-purple-a200: map-get($clr-deep-purple-list, \"a200\");\n$clr-deep-purple-a400: map-get($clr-deep-purple-list, \"a400\");\n$clr-deep-purple-a700: map-get($clr-deep-purple-list, \"a700\");\n\n\n//\n// Indigo\n//\n\n$clr-indigo-list: (\n \"base\": #3f51b5,\n \"50\": #e8eaf6,\n \"100\": #c5cae9,\n \"200\": #9fa8da,\n \"300\": #7986cb,\n \"400\": #5c6bc0,\n \"500\": #3f51b5,\n \"600\": #3949ab,\n \"700\": #303f9f,\n \"800\": #283593,\n \"900\": #1a237e,\n \"a100\": #8c9eff,\n \"a200\": #536dfe,\n \"a400\": #3d5afe,\n \"a700\": #304ffe\n);\n\n$clr-indigo: map-get($clr-indigo-list, \"base\");\n\n$clr-indigo-50: map-get($clr-indigo-list, \"50\");\n$clr-indigo-100: map-get($clr-indigo-list, \"100\");\n$clr-indigo-200: map-get($clr-indigo-list, \"200\");\n$clr-indigo-300: map-get($clr-indigo-list, \"300\");\n$clr-indigo-400: map-get($clr-indigo-list, \"400\");\n$clr-indigo-500: map-get($clr-indigo-list, \"500\");\n$clr-indigo-600: map-get($clr-indigo-list, \"600\");\n$clr-indigo-700: map-get($clr-indigo-list, \"700\");\n$clr-indigo-800: map-get($clr-indigo-list, \"800\");\n$clr-indigo-900: map-get($clr-indigo-list, \"900\");\n$clr-indigo-a100: map-get($clr-indigo-list, \"a100\");\n$clr-indigo-a200: map-get($clr-indigo-list, \"a200\");\n$clr-indigo-a400: map-get($clr-indigo-list, \"a400\");\n$clr-indigo-a700: map-get($clr-indigo-list, \"a700\");\n\n\n//\n// Blue\n//\n\n$clr-blue-list: (\n \"base\": #2196f3,\n \"50\": #e3f2fd,\n \"100\": #bbdefb,\n \"200\": #90caf9,\n \"300\": #64b5f6,\n \"400\": #42a5f5,\n \"500\": #2196f3,\n \"600\": #1e88e5,\n \"700\": #1976d2,\n \"800\": #1565c0,\n \"900\": #0d47a1,\n \"a100\": #82b1ff,\n \"a200\": #448aff,\n \"a400\": #2979ff,\n \"a700\": #2962ff\n);\n\n$clr-blue: map-get($clr-blue-list, \"base\");\n\n$clr-blue-50: map-get($clr-blue-list, \"50\");\n$clr-blue-100: map-get($clr-blue-list, \"100\");\n$clr-blue-200: map-get($clr-blue-list, \"200\");\n$clr-blue-300: map-get($clr-blue-list, \"300\");\n$clr-blue-400: map-get($clr-blue-list, \"400\");\n$clr-blue-500: map-get($clr-blue-list, \"500\");\n$clr-blue-600: map-get($clr-blue-list, \"600\");\n$clr-blue-700: map-get($clr-blue-list, \"700\");\n$clr-blue-800: map-get($clr-blue-list, \"800\");\n$clr-blue-900: map-get($clr-blue-list, \"900\");\n$clr-blue-a100: map-get($clr-blue-list, \"a100\");\n$clr-blue-a200: map-get($clr-blue-list, \"a200\");\n$clr-blue-a400: map-get($clr-blue-list, \"a400\");\n$clr-blue-a700: map-get($clr-blue-list, \"a700\");\n\n\n//\n// Light Blue\n//\n\n$clr-light-blue-list: (\n \"base\": #03a9f4,\n \"50\": #e1f5fe,\n \"100\": #b3e5fc,\n \"200\": #81d4fa,\n \"300\": #4fc3f7,\n \"400\": #29b6f6,\n \"500\": #03a9f4,\n \"600\": #039be5,\n \"700\": #0288d1,\n \"800\": #0277bd,\n \"900\": #01579b,\n \"a100\": #80d8ff,\n \"a200\": #40c4ff,\n \"a400\": #00b0ff,\n \"a700\": #0091ea\n);\n\n$clr-light-blue: map-get($clr-light-blue-list, \"base\");\n\n$clr-light-blue-50: map-get($clr-light-blue-list, \"50\");\n$clr-light-blue-100: map-get($clr-light-blue-list, \"100\");\n$clr-light-blue-200: map-get($clr-light-blue-list, \"200\");\n$clr-light-blue-300: map-get($clr-light-blue-list, \"300\");\n$clr-light-blue-400: map-get($clr-light-blue-list, \"400\");\n$clr-light-blue-500: map-get($clr-light-blue-list, \"500\");\n$clr-light-blue-600: map-get($clr-light-blue-list, \"600\");\n$clr-light-blue-700: map-get($clr-light-blue-list, \"700\");\n$clr-light-blue-800: map-get($clr-light-blue-list, \"800\");\n$clr-light-blue-900: map-get($clr-light-blue-list, \"900\");\n$clr-light-blue-a100: map-get($clr-light-blue-list, \"a100\");\n$clr-light-blue-a200: map-get($clr-light-blue-list, \"a200\");\n$clr-light-blue-a400: map-get($clr-light-blue-list, \"a400\");\n$clr-light-blue-a700: map-get($clr-light-blue-list, \"a700\");\n\n\n//\n// Cyan\n//\n\n$clr-cyan-list: (\n \"base\": #00bcd4,\n \"50\": #e0f7fa,\n \"100\": #b2ebf2,\n \"200\": #80deea,\n \"300\": #4dd0e1,\n \"400\": #26c6da,\n \"500\": #00bcd4,\n \"600\": #00acc1,\n \"700\": #0097a7,\n \"800\": #00838f,\n \"900\": #006064,\n \"a100\": #84ffff,\n \"a200\": #18ffff,\n \"a400\": #00e5ff,\n \"a700\": #00b8d4\n);\n\n$clr-cyan: map-get($clr-cyan-list, \"base\");\n\n$clr-cyan-50: map-get($clr-cyan-list, \"50\");\n$clr-cyan-100: map-get($clr-cyan-list, \"100\");\n$clr-cyan-200: map-get($clr-cyan-list, \"200\");\n$clr-cyan-300: map-get($clr-cyan-list, \"300\");\n$clr-cyan-400: map-get($clr-cyan-list, \"400\");\n$clr-cyan-500: map-get($clr-cyan-list, \"500\");\n$clr-cyan-600: map-get($clr-cyan-list, \"600\");\n$clr-cyan-700: map-get($clr-cyan-list, \"700\");\n$clr-cyan-800: map-get($clr-cyan-list, \"800\");\n$clr-cyan-900: map-get($clr-cyan-list, \"900\");\n$clr-cyan-a100: map-get($clr-cyan-list, \"a100\");\n$clr-cyan-a200: map-get($clr-cyan-list, \"a200\");\n$clr-cyan-a400: map-get($clr-cyan-list, \"a400\");\n$clr-cyan-a700: map-get($clr-cyan-list, \"a700\");\n\n\n//\n// Teal\n//\n\n$clr-teal-list: (\n \"base\": #009688,\n \"50\": #e0f2f1,\n \"100\": #b2dfdb,\n \"200\": #80cbc4,\n \"300\": #4db6ac,\n \"400\": #26a69a,\n \"500\": #009688,\n \"600\": #00897b,\n \"700\": #00796b,\n \"800\": #00695c,\n \"900\": #004d40,\n \"a100\": #a7ffeb,\n \"a200\": #64ffda,\n \"a400\": #1de9b6,\n \"a700\": #00bfa5\n);\n\n$clr-teal: map-get($clr-teal-list, \"base\");\n\n$clr-teal-50: map-get($clr-teal-list, \"50\");\n$clr-teal-100: map-get($clr-teal-list, \"100\");\n$clr-teal-200: map-get($clr-teal-list, \"200\");\n$clr-teal-300: map-get($clr-teal-list, \"300\");\n$clr-teal-400: map-get($clr-teal-list, \"400\");\n$clr-teal-500: map-get($clr-teal-list, \"500\");\n$clr-teal-600: map-get($clr-teal-list, \"600\");\n$clr-teal-700: map-get($clr-teal-list, \"700\");\n$clr-teal-800: map-get($clr-teal-list, \"800\");\n$clr-teal-900: map-get($clr-teal-list, \"900\");\n$clr-teal-a100: map-get($clr-teal-list, \"a100\");\n$clr-teal-a200: map-get($clr-teal-list, \"a200\");\n$clr-teal-a400: map-get($clr-teal-list, \"a400\");\n$clr-teal-a700: map-get($clr-teal-list, \"a700\");\n\n\n//\n// Green\n//\n\n$clr-green-list: (\n \"base\": #4caf50,\n \"50\": #e8f5e9,\n \"100\": #c8e6c9,\n \"200\": #a5d6a7,\n \"300\": #81c784,\n \"400\": #66bb6a,\n \"500\": #4caf50,\n \"600\": #43a047,\n \"700\": #388e3c,\n \"800\": #2e7d32,\n \"900\": #1b5e20,\n \"a100\": #b9f6ca,\n \"a200\": #69f0ae,\n \"a400\": #00e676,\n \"a700\": #00c853\n);\n\n$clr-green: map-get($clr-green-list, \"base\");\n\n$clr-green-50: map-get($clr-green-list, \"50\");\n$clr-green-100: map-get($clr-green-list, \"100\");\n$clr-green-200: map-get($clr-green-list, \"200\");\n$clr-green-300: map-get($clr-green-list, \"300\");\n$clr-green-400: map-get($clr-green-list, \"400\");\n$clr-green-500: map-get($clr-green-list, \"500\");\n$clr-green-600: map-get($clr-green-list, \"600\");\n$clr-green-700: map-get($clr-green-list, \"700\");\n$clr-green-800: map-get($clr-green-list, \"800\");\n$clr-green-900: map-get($clr-green-list, \"900\");\n$clr-green-a100: map-get($clr-green-list, \"a100\");\n$clr-green-a200: map-get($clr-green-list, \"a200\");\n$clr-green-a400: map-get($clr-green-list, \"a400\");\n$clr-green-a700: map-get($clr-green-list, \"a700\");\n\n\n//\n// Light green\n//\n\n$clr-light-green-list: (\n \"base\": #8bc34a,\n \"50\": #f1f8e9,\n \"100\": #dcedc8,\n \"200\": #c5e1a5,\n \"300\": #aed581,\n \"400\": #9ccc65,\n \"500\": #8bc34a,\n \"600\": #7cb342,\n \"700\": #689f38,\n \"800\": #558b2f,\n \"900\": #33691e,\n \"a100\": #ccff90,\n \"a200\": #b2ff59,\n \"a400\": #76ff03,\n \"a700\": #64dd17\n);\n\n$clr-light-green: map-get($clr-light-green-list, \"base\");\n\n$clr-light-green-50: map-get($clr-light-green-list, \"50\");\n$clr-light-green-100: map-get($clr-light-green-list, \"100\");\n$clr-light-green-200: map-get($clr-light-green-list, \"200\");\n$clr-light-green-300: map-get($clr-light-green-list, \"300\");\n$clr-light-green-400: map-get($clr-light-green-list, \"400\");\n$clr-light-green-500: map-get($clr-light-green-list, \"500\");\n$clr-light-green-600: map-get($clr-light-green-list, \"600\");\n$clr-light-green-700: map-get($clr-light-green-list, \"700\");\n$clr-light-green-800: map-get($clr-light-green-list, \"800\");\n$clr-light-green-900: map-get($clr-light-green-list, \"900\");\n$clr-light-green-a100: map-get($clr-light-green-list, \"a100\");\n$clr-light-green-a200: map-get($clr-light-green-list, \"a200\");\n$clr-light-green-a400: map-get($clr-light-green-list, \"a400\");\n$clr-light-green-a700: map-get($clr-light-green-list, \"a700\");\n\n\n//\n// Lime\n//\n\n$clr-lime-list: (\n \"base\": #cddc39,\n \"50\": #f9fbe7,\n \"100\": #f0f4c3,\n \"200\": #e6ee9c,\n \"300\": #dce775,\n \"400\": #d4e157,\n \"500\": #cddc39,\n \"600\": #c0ca33,\n \"700\": #afb42b,\n \"800\": #9e9d24,\n \"900\": #827717,\n \"a100\": #f4ff81,\n \"a200\": #eeff41,\n \"a400\": #c6ff00,\n \"a700\": #aeea00\n);\n\n$clr-lime: map-get($clr-lime-list, \"base\");\n\n$clr-lime-50: map-get($clr-lime-list, \"50\");\n$clr-lime-100: map-get($clr-lime-list, \"100\");\n$clr-lime-200: map-get($clr-lime-list, \"200\");\n$clr-lime-300: map-get($clr-lime-list, \"300\");\n$clr-lime-400: map-get($clr-lime-list, \"400\");\n$clr-lime-500: map-get($clr-lime-list, \"500\");\n$clr-lime-600: map-get($clr-lime-list, \"600\");\n$clr-lime-700: map-get($clr-lime-list, \"700\");\n$clr-lime-800: map-get($clr-lime-list, \"800\");\n$clr-lime-900: map-get($clr-lime-list, \"900\");\n$clr-lime-a100: map-get($clr-lime-list, \"a100\");\n$clr-lime-a200: map-get($clr-lime-list, \"a200\");\n$clr-lime-a400: map-get($clr-lime-list, \"a400\");\n$clr-lime-a700: map-get($clr-lime-list, \"a700\");\n\n\n//\n// Yellow\n//\n\n$clr-yellow-list: (\n \"base\": #ffeb3b,\n \"50\": #fffde7,\n \"100\": #fff9c4,\n \"200\": #fff59d,\n \"300\": #fff176,\n \"400\": #ffee58,\n \"500\": #ffeb3b,\n \"600\": #fdd835,\n \"700\": #fbc02d,\n \"800\": #f9a825,\n \"900\": #f57f17,\n \"a100\": #ffff8d,\n \"a200\": #ffff00,\n \"a400\": #ffea00,\n \"a700\": #ffd600\n);\n\n$clr-yellow: map-get($clr-yellow-list, \"base\");\n\n$clr-yellow-50: map-get($clr-yellow-list, \"50\");\n$clr-yellow-100: map-get($clr-yellow-list, \"100\");\n$clr-yellow-200: map-get($clr-yellow-list, \"200\");\n$clr-yellow-300: map-get($clr-yellow-list, \"300\");\n$clr-yellow-400: map-get($clr-yellow-list, \"400\");\n$clr-yellow-500: map-get($clr-yellow-list, \"500\");\n$clr-yellow-600: map-get($clr-yellow-list, \"600\");\n$clr-yellow-700: map-get($clr-yellow-list, \"700\");\n$clr-yellow-800: map-get($clr-yellow-list, \"800\");\n$clr-yellow-900: map-get($clr-yellow-list, \"900\");\n$clr-yellow-a100: map-get($clr-yellow-list, \"a100\");\n$clr-yellow-a200: map-get($clr-yellow-list, \"a200\");\n$clr-yellow-a400: map-get($clr-yellow-list, \"a400\");\n$clr-yellow-a700: map-get($clr-yellow-list, \"a700\");\n\n\n//\n// amber\n//\n\n$clr-amber-list: (\n \"base\": #ffc107,\n \"50\": #fff8e1,\n \"100\": #ffecb3,\n \"200\": #ffe082,\n \"300\": #ffd54f,\n \"400\": #ffca28,\n \"500\": #ffc107,\n \"600\": #ffb300,\n \"700\": #ffa000,\n \"800\": #ff8f00,\n \"900\": #ff6f00,\n \"a100\": #ffe57f,\n \"a200\": #ffd740,\n \"a400\": #ffc400,\n \"a700\": #ffab00\n);\n\n$clr-amber: map-get($clr-amber-list, \"base\");\n\n$clr-amber-50: map-get($clr-amber-list, \"50\");\n$clr-amber-100: map-get($clr-amber-list, \"100\");\n$clr-amber-200: map-get($clr-amber-list, \"200\");\n$clr-amber-300: map-get($clr-amber-list, \"300\");\n$clr-amber-400: map-get($clr-amber-list, \"400\");\n$clr-amber-500: map-get($clr-amber-list, \"500\");\n$clr-amber-600: map-get($clr-amber-list, \"600\");\n$clr-amber-700: map-get($clr-amber-list, \"700\");\n$clr-amber-800: map-get($clr-amber-list, \"800\");\n$clr-amber-900: map-get($clr-amber-list, \"900\");\n$clr-amber-a100: map-get($clr-amber-list, \"a100\");\n$clr-amber-a200: map-get($clr-amber-list, \"a200\");\n$clr-amber-a400: map-get($clr-amber-list, \"a400\");\n$clr-amber-a700: map-get($clr-amber-list, \"a700\");\n\n\n//\n// Orange\n//\n\n$clr-orange-list: (\n \"base\": #ff9800,\n \"50\": #fff3e0,\n \"100\": #ffe0b2,\n \"200\": #ffcc80,\n \"300\": #ffb74d,\n \"400\": #ffa726,\n \"500\": #ff9800,\n \"600\": #fb8c00,\n \"700\": #f57c00,\n \"800\": #ef6c00,\n \"900\": #e65100,\n \"a100\": #ffd180,\n \"a200\": #ffab40,\n \"a400\": #ff9100,\n \"a700\": #ff6d00\n);\n\n$clr-orange: map-get($clr-orange-list, \"base\");\n\n$clr-orange-50: map-get($clr-orange-list, \"50\");\n$clr-orange-100: map-get($clr-orange-list, \"100\");\n$clr-orange-200: map-get($clr-orange-list, \"200\");\n$clr-orange-300: map-get($clr-orange-list, \"300\");\n$clr-orange-400: map-get($clr-orange-list, \"400\");\n$clr-orange-500: map-get($clr-orange-list, \"500\");\n$clr-orange-600: map-get($clr-orange-list, \"600\");\n$clr-orange-700: map-get($clr-orange-list, \"700\");\n$clr-orange-800: map-get($clr-orange-list, \"800\");\n$clr-orange-900: map-get($clr-orange-list, \"900\");\n$clr-orange-a100: map-get($clr-orange-list, \"a100\");\n$clr-orange-a200: map-get($clr-orange-list, \"a200\");\n$clr-orange-a400: map-get($clr-orange-list, \"a400\");\n$clr-orange-a700: map-get($clr-orange-list, \"a700\");\n\n\n//\n// Deep orange\n//\n\n$clr-deep-orange-list: (\n \"base\": #ff5722,\n \"50\": #fbe9e7,\n \"100\": #ffccbc,\n \"200\": #ffab91,\n \"300\": #ff8a65,\n \"400\": #ff7043,\n \"500\": #ff5722,\n \"600\": #f4511e,\n \"700\": #e64a19,\n \"800\": #d84315,\n \"900\": #bf360c,\n \"a100\": #ff9e80,\n \"a200\": #ff6e40,\n \"a400\": #ff3d00,\n \"a700\": #dd2c00\n);\n\n$clr-deep-orange: map-get($clr-deep-orange-list, \"base\");\n\n$clr-deep-orange-50: map-get($clr-deep-orange-list, \"50\");\n$clr-deep-orange-100: map-get($clr-deep-orange-list, \"100\");\n$clr-deep-orange-200: map-get($clr-deep-orange-list, \"200\");\n$clr-deep-orange-300: map-get($clr-deep-orange-list, \"300\");\n$clr-deep-orange-400: map-get($clr-deep-orange-list, \"400\");\n$clr-deep-orange-500: map-get($clr-deep-orange-list, \"500\");\n$clr-deep-orange-600: map-get($clr-deep-orange-list, \"600\");\n$clr-deep-orange-700: map-get($clr-deep-orange-list, \"700\");\n$clr-deep-orange-800: map-get($clr-deep-orange-list, \"800\");\n$clr-deep-orange-900: map-get($clr-deep-orange-list, \"900\");\n$clr-deep-orange-a100: map-get($clr-deep-orange-list, \"a100\");\n$clr-deep-orange-a200: map-get($clr-deep-orange-list, \"a200\");\n$clr-deep-orange-a400: map-get($clr-deep-orange-list, \"a400\");\n$clr-deep-orange-a700: map-get($clr-deep-orange-list, \"a700\");\n\n\n//\n// Brown\n//\n\n$clr-brown-list: (\n \"base\": #795548,\n \"50\": #efebe9,\n \"100\": #d7ccc8,\n \"200\": #bcaaa4,\n \"300\": #a1887f,\n \"400\": #8d6e63,\n \"500\": #795548,\n \"600\": #6d4c41,\n \"700\": #5d4037,\n \"800\": #4e342e,\n \"900\": #3e2723,\n);\n\n$clr-brown: map-get($clr-brown-list, \"base\");\n\n$clr-brown-50: map-get($clr-brown-list, \"50\");\n$clr-brown-100: map-get($clr-brown-list, \"100\");\n$clr-brown-200: map-get($clr-brown-list, \"200\");\n$clr-brown-300: map-get($clr-brown-list, \"300\");\n$clr-brown-400: map-get($clr-brown-list, \"400\");\n$clr-brown-500: map-get($clr-brown-list, \"500\");\n$clr-brown-600: map-get($clr-brown-list, \"600\");\n$clr-brown-700: map-get($clr-brown-list, \"700\");\n$clr-brown-800: map-get($clr-brown-list, \"800\");\n$clr-brown-900: map-get($clr-brown-list, \"900\");\n\n\n//\n// Grey\n//\n\n$clr-grey-list: (\n \"base\": #9e9e9e,\n \"50\": #fafafa,\n \"100\": #f5f5f5,\n \"200\": #eeeeee,\n \"300\": #e0e0e0,\n \"400\": #bdbdbd,\n \"500\": #9e9e9e,\n \"600\": #757575,\n \"700\": #616161,\n \"800\": #424242,\n \"900\": #212121,\n);\n\n$clr-grey: map-get($clr-grey-list, \"base\");\n\n$clr-grey-50: map-get($clr-grey-list, \"50\");\n$clr-grey-100: map-get($clr-grey-list, \"100\");\n$clr-grey-200: map-get($clr-grey-list, \"200\");\n$clr-grey-300: map-get($clr-grey-list, \"300\");\n$clr-grey-400: map-get($clr-grey-list, \"400\");\n$clr-grey-500: map-get($clr-grey-list, \"500\");\n$clr-grey-600: map-get($clr-grey-list, \"600\");\n$clr-grey-700: map-get($clr-grey-list, \"700\");\n$clr-grey-800: map-get($clr-grey-list, \"800\");\n$clr-grey-900: map-get($clr-grey-list, \"900\");\n\n\n//\n// Blue grey\n//\n\n$clr-blue-grey-list: (\n \"base\": #607d8b,\n \"50\": #eceff1,\n \"100\": #cfd8dc,\n \"200\": #b0bec5,\n \"300\": #90a4ae,\n \"400\": #78909c,\n \"500\": #607d8b,\n \"600\": #546e7a,\n \"700\": #455a64,\n \"800\": #37474f,\n \"900\": #263238,\n);\n\n$clr-blue-grey: map-get($clr-blue-grey-list, \"base\");\n\n$clr-blue-grey-50: map-get($clr-blue-grey-list, \"50\");\n$clr-blue-grey-100: map-get($clr-blue-grey-list, \"100\");\n$clr-blue-grey-200: map-get($clr-blue-grey-list, \"200\");\n$clr-blue-grey-300: map-get($clr-blue-grey-list, \"300\");\n$clr-blue-grey-400: map-get($clr-blue-grey-list, \"400\");\n$clr-blue-grey-500: map-get($clr-blue-grey-list, \"500\");\n$clr-blue-grey-600: map-get($clr-blue-grey-list, \"600\");\n$clr-blue-grey-700: map-get($clr-blue-grey-list, \"700\");\n$clr-blue-grey-800: map-get($clr-blue-grey-list, \"800\");\n$clr-blue-grey-900: map-get($clr-blue-grey-list, \"900\");\n\n\n//\n// Black\n//\n\n$clr-black-list: (\n \"base\": #000\n);\n\n$clr-black: map-get($clr-black-list, \"base\");\n\n\n//\n// White\n//\n\n$clr-white-list: (\n \"base\": #fff\n);\n\n$clr-white: map-get($clr-white-list, \"base\");\n\n\n//\n// List for all Colors for looping\n//\n\n$clr-list-all: (\n \"red\": $clr-red-list,\n \"pink\": $clr-pink-list,\n \"purple\": $clr-purple-list,\n \"deep-purple\": $clr-deep-purple-list,\n \"indigo\": $clr-indigo-list,\n \"blue\": $clr-blue-list,\n \"light-blue\": $clr-light-blue-list,\n \"cyan\": $clr-cyan-list,\n \"teal\": $clr-teal-list,\n \"green\": $clr-green-list,\n \"light-green\": $clr-light-green-list,\n \"lime\": $clr-lime-list,\n \"yellow\": $clr-yellow-list,\n \"amber\": $clr-amber-list,\n \"orange\": $clr-orange-list,\n \"deep-orange\": $clr-deep-orange-list,\n \"brown\": $clr-brown-list,\n \"grey\": $clr-grey-list,\n \"blue-grey\": $clr-blue-grey-list,\n \"black\": $clr-black-list,\n \"white\": $clr-white-list\n);\n\n\n//\n// Typography\n//\n\n$clr-ui-display-4: $clr-grey-600;\n$clr-ui-display-3: $clr-grey-600;\n$clr-ui-display-2: $clr-grey-600;\n$clr-ui-display-1: $clr-grey-600;\n$clr-ui-headline: $clr-grey-900;\n$clr-ui-title: $clr-grey-900;\n$clr-ui-subhead-1: $clr-grey-900;\n$clr-ui-body-2: $clr-grey-900;\n$clr-ui-body-1: $clr-grey-900;\n$clr-ui-caption: $clr-grey-600;\n$clr-ui-menu: $clr-grey-900;\n$clr-ui-button: $clr-grey-900;\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-footnotes-icon: svg-load(\"material/keyboard-return.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Footnote container\n .footnote {\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n\n // Footnote list - omit left indentation\n > ol {\n margin-left: 0;\n\n // Footnote item - footnote items can contain lists, so we need to scope\n // the spacing adjustments to the top-level footnote item.\n > li {\n transition: color 125ms;\n\n // Darken color on target\n &:target {\n color: var(--md-default-fg-color);\n }\n\n // Show backreferences on footnote hover\n &:hover .footnote-backref,\n &:target .footnote-backref {\n transform: translateX(0);\n opacity: 1;\n }\n\n // Adjust spacing on first child\n > :first-child {\n margin-top: 0;\n }\n }\n }\n }\n\n // Footnote reference\n .footnote-ref {\n font-weight: 700;\n font-size: px2em(12px, 16px);\n\n // Hack: increase specificity to override default\n html & {\n outline-offset: px2rem(2px);\n }\n }\n\n // Footnote backreference\n .footnote-backref {\n display: inline-block;\n color: var(--md-typeset-a-color);\n // Hack: omit Unicode arrow for replacement with icon\n font-size: 0;\n vertical-align: text-bottom;\n transform: translateX(px2rem(5px));\n opacity: 0;\n transition:\n color 250ms,\n transform 250ms 250ms,\n opacity 125ms 250ms;\n\n // [print]: Show footnote backreferences\n @media print {\n color: var(--md-typeset-a-color);\n transform: translateX(0);\n opacity: 1;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-5px));\n }\n\n // Adjust color on hover\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Footnote backreference icon\n &::before {\n display: inline-block;\n width: px2rem(16px);\n height: px2rem(16px);\n background-color: currentColor;\n mask-image: var(--md-footnotes-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n }\n\n // Footnote reference wrapper\n [id^=\"fnref:\"]:target {\n scroll-margin-top: initial;\n margin-top: -1 * px2rem(48px + 24px - 4px);\n padding-top: px2rem(48px + 24px - 4px);\n\n // Show outline for all devices\n > .footnote-ref {\n outline: auto;\n }\n }\n\n // Footnote wrapper\n [id^=\"fn:\"]:target {\n scroll-margin-top: initial;\n margin-top: -1 * px2rem(48px + 24px - 3px);\n padding-top: px2rem(48px + 24px - 3px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Headerlink\n .headerlink {\n display: inline-block;\n margin-left: px2rem(10px);\n color: var(--md-default-fg-color--lighter);\n opacity: 0;\n transition:\n color 250ms,\n opacity 125ms;\n\n // [print]: Hide headerlinks\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(10px);\n margin-left: initial;\n }\n }\n\n // Show headerlinks on parent hover\n :hover > .headerlink,\n :target > .headerlink,\n .headerlink:focus {\n opacity: 1;\n transition:\n color 250ms,\n opacity 125ms;\n }\n\n // Adjust color on parent target or focus/hover\n :target > .headerlink,\n .headerlink:focus,\n .headerlink:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Adjust scroll offset for all elements with `id` attributes - general scroll\n // margin offset for anything that can be targeted. Browser support is pretty\n // decent by now, but Edge <79 and Safari (iOS and macOS) still don't support\n // it properly, so we settle with a cross-browser anchor correction solution.\n :target {\n scroll-margin-top: px2rem(48px + 24px);\n }\n\n // Adjust scroll offset for headlines of level 1-3\n h1:target,\n h2:target,\n h3:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px - 4px);\n padding-top: px2rem(48px + 24px - 4px);\n content: \"\";\n }\n }\n\n // Adjust scroll offset for headlines of level 4\n h4:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px - 3px);\n padding-top: px2rem(48px + 24px - 3px);\n content: \"\";\n }\n }\n\n // Adjust scroll offset for headlines of level 5-6\n h5:target,\n h6:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px);\n padding-top: px2rem(48px + 24px);\n content: \"\";\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Arithmatex container\n div.arithmatex {\n overflow: auto;\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n margin: 0 px2rem(-16px);\n }\n\n // Arithmatex content\n > * {\n width: min-content;\n // stylelint-disable-next-line declaration-no-important\n margin: 1em auto !important;\n padding: 0 px2rem(16px);\n touch-action: auto;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Deletion, addition or comment\n del.critic,\n ins.critic,\n .critic.comment {\n box-decoration-break: clone;\n }\n\n // Deletion\n del.critic {\n background-color: var(--md-typeset-del-color);\n }\n\n // Addition\n ins.critic {\n background-color: var(--md-typeset-ins-color);\n }\n\n // Comment\n .critic.comment {\n color: var(--md-code-hl-comment-color);\n\n // Comment opening mark\n &::before {\n content: \"/* \";\n }\n\n // Comment closing mark\n &::after {\n content: \" */\";\n }\n }\n\n // Critic block\n .critic.block {\n display: block;\n margin: 1em 0;\n padding-right: px2rem(16px);\n padding-left: px2rem(16px);\n overflow: auto;\n box-shadow: none;\n\n // Adjust spacing on first child\n > :first-child {\n margin-top: 0.5em;\n }\n\n // Adjust spacing on last child\n > :last-child {\n margin-bottom: 0.5em;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-details-icon: svg-load(\"material/chevron-right.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Details\n details {\n @extend .admonition;\n\n display: flow-root;\n padding-top: 0;\n overflow: visible;\n\n // Details title icon - rotate icon on transition to open state\n &[open] > summary::after {\n transform: rotate(90deg);\n }\n\n // Adjust spacing for details in closed state\n &:not([open]) {\n padding-bottom: 0;\n box-shadow: none;\n\n // Hack: we cannot set `overflow: hidden` on the `details` element (which\n // is why we set it to `overflow: visible`, as the outline would not be\n // visible when focusing. Therefore, we must set the border radius on the\n // summary explicitly.\n > summary {\n border-radius: px2rem(2px);\n }\n }\n\n // Hack: omit margin collapse\n &::after {\n display: table;\n content: \"\";\n }\n }\n\n // Details title\n summary {\n @extend .admonition-title;\n\n display: block;\n min-height: px2rem(20px);\n padding: px2rem(8px) px2rem(36px) px2rem(8px) px2rem(40px);\n border-top-left-radius: px2rem(2px);\n border-top-right-radius: px2rem(2px);\n cursor: pointer;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: px2rem(8px) px2rem(44px) px2rem(8px) px2rem(36px);\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Details marker\n &::after {\n position: absolute;\n top: px2rem(8px);\n right: px2rem(8px);\n width: px2rem(20px);\n height: px2rem(20px);\n background-color: currentColor;\n mask-image: var(--md-details-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transform: rotate(0deg);\n transition: transform 250ms;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(8px);\n transform: rotate(180deg);\n }\n }\n\n // Hide native details marker\n &::marker,\n &::-webkit-details-marker {\n display: none;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Emoji and icon container\n .emojione,\n .twemoji,\n .gemoji {\n display: inline-flex;\n height: px2em(18px);\n vertical-align: text-top;\n\n // Icon - inlined via mkdocs-material-extensions\n svg {\n width: px2em(18px);\n max-height: 100%;\n fill: currentColor;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: syntax highlighting\n// ----------------------------------------------------------------------------\n\n// Code block\n.highlight {\n .o, // Operator\n .ow { // Operator, word\n color: var(--md-code-hl-operator-color);\n }\n\n .p { // Punctuation\n color: var(--md-code-hl-punctuation-color);\n }\n\n .cpf, // Comment, preprocessor file\n .l, // Literal\n .s, // Literal, string\n .sb, // Literal, string backticks\n .sc, // Literal, string char\n .s2, // Literal, string double\n .si, // Literal, string interpol\n .s1, // Literal, string single\n .ss { // Literal, string symbol\n color: var(--md-code-hl-string-color);\n }\n\n .cp, // Comment, pre-processor\n .se, // Literal, string escape\n .sh, // Literal, string heredoc\n .sr, // Literal, string regex\n .sx { // Literal, string other\n color: var(--md-code-hl-special-color);\n }\n\n .m, // Number\n .mb, // Number, binary\n .mf, // Number, float\n .mh, // Number, hex\n .mi, // Number, integer\n .il, // Number, integer long\n .mo { // Number, octal\n color: var(--md-code-hl-number-color);\n }\n\n .k, // Keyword,\n .kd, // Keyword, declaration\n .kn, // Keyword, namespace\n .kp, // Keyword, pseudo\n .kr, // Keyword, reserved\n .kt { // Keyword, type\n color: var(--md-code-hl-keyword-color);\n }\n\n .kc, // Keyword, constant\n .n { // Name\n color: var(--md-code-hl-name-color);\n }\n\n .no, // Name, constant\n .nb, // Name, builtin\n .bp { // Name, builtin pseudo\n color: var(--md-code-hl-constant-color);\n }\n\n .nc, // Name, class\n .ne, // Name, exception\n .nf, // Name, function\n .nn { // Name, namespace\n color: var(--md-code-hl-function-color);\n }\n\n .nd, // Name, decorator\n .ni, // Name, entity\n .nl, // Name, label\n .nt { // Name, tag\n color: var(--md-code-hl-keyword-color);\n }\n\n .c, // Comment\n .cm, // Comment, multiline\n .c1, // Comment, single\n .ch, // Comment, shebang\n .cs, // Comment, special\n .sd { // Literal, string doc\n color: var(--md-code-hl-comment-color);\n }\n\n .na, // Name, attribute\n .nv, // Variable,\n .vc, // Variable, class\n .vg, // Variable, global\n .vi { // Variable, instance\n color: var(--md-code-hl-variable-color);\n }\n\n .ge, // Generic, emph\n .gr, // Generic, error\n .gh, // Generic, heading\n .go, // Generic, output\n .gp, // Generic, prompt\n .gs, // Generic, strong\n .gu, // Generic, subheading\n .gt { // Generic, traceback\n color: var(--md-code-hl-generic-color);\n }\n\n .gd, // Diff, delete\n .gi { // Diff, insert\n margin: 0 px2em(-2px);\n padding: 0 px2em(2px);\n border-radius: px2rem(2px);\n }\n\n .gd { // Diff, delete\n background-color: var(--md-typeset-del-color);\n }\n\n .gi { // Diff, insert\n background-color: var(--md-typeset-ins-color);\n }\n\n // Highlighted line\n .hll {\n display: block;\n margin: 0 px2em(-16px, 13.6px);\n padding: 0 px2em(16px, 13.6px);\n background-color: var(--md-code-hl-color);\n }\n\n // Code block line numbers (inline)\n [data-linenos]::before {\n position: sticky;\n left: px2em(-16px, 13.6px);\n float: left;\n margin-right: px2em(16px, 13.6px);\n margin-left: px2em(-16px, 13.6px);\n padding-left: px2em(16px, 13.6px);\n color: var(--md-default-fg-color--light);\n background-color: var(--md-code-bg-color);\n box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;\n content: attr(data-linenos);\n user-select: none;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: layout\n// ----------------------------------------------------------------------------\n\n// Code block with line numbers\n.highlighttable {\n display: flow-root;\n overflow: hidden;\n\n // Set table elements to block layout, because otherwise the whole flexbox\n // hacking won't work correctly\n tbody,\n td {\n display: block;\n padding: 0;\n }\n\n // We need to use flexbox layout, because otherwise it's not possible to\n // make the code container scroll while keeping the line numbers static\n tr {\n display: flex;\n }\n\n // The pre tags are nested inside a table, so we need to omit the margin\n // because it collapses below all the overflows\n pre {\n margin: 0;\n }\n\n // Code block line numbers - disable user selection, so code can be easily\n // copied without accidentally also copying the line numbers\n .linenos {\n padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);\n padding-right: 0;\n font-size: px2em(13.6px);\n background-color: var(--md-code-bg-color);\n user-select: none;\n }\n\n // Code block line numbers container\n .linenodiv {\n padding-right: px2em(8px, 13.6px);\n box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;\n\n // Adjust colors and alignment\n pre {\n color: var(--md-default-fg-color--light);\n text-align: right;\n }\n }\n\n // Code block container - stretch to remaining space\n .code {\n flex: 1;\n overflow: hidden;\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Code block with line numbers\n .highlighttable {\n margin: 1em 0;\n direction: ltr;\n border-radius: px2rem(2px);\n\n // Omit rounded borders on contained code block\n code {\n border-radius: 0;\n }\n }\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n\n // Top-level code block\n > .highlight {\n margin: 1em px2rem(-16px);\n\n // Highlighted line\n .hll {\n margin: 0 px2rem(-16px);\n padding: 0 px2rem(16px);\n }\n\n // Omit rounded borders\n code {\n border-radius: 0;\n }\n }\n\n // Top-level code block with line numbers\n > .highlighttable {\n margin: 1em px2rem(-16px);\n border-radius: 0;\n\n // Highlighted line\n .hll {\n margin: 0 px2rem(-16px);\n padding: 0 px2rem(16px);\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Tabbed block content\n .tabbed-content {\n display: none;\n order: 99;\n width: 100%;\n box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest);\n\n // [print]: Show all tabs (even hidden ones) when printing\n @media print {\n display: block;\n order: initial;\n }\n\n // Code block is the only child of a tab - remove margin and mirror\n // previous (now deprecated) SuperFences code block grouping behavior\n > pre:only-child,\n > .highlight:only-child pre,\n > .highlighttable:only-child {\n margin: 0;\n\n // Omit rounded borders\n > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n }\n\n // Adjust spacing for nested tab\n > .tabbed-set {\n margin: 0;\n }\n }\n\n // Tabbed block container\n .tabbed-set {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n margin: 1em 0;\n border-radius: px2rem(2px);\n\n // Tab radio button - the Tabbed extension will generate radio buttons with\n // labels, so tabs can be triggered without the necessity for JavaScript.\n // This is pretty cool, as it has great accessibility out-of-the box, so\n // we just hide the radio button and toggle the label color for indication.\n > input {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n\n // Tab label for checked radio button\n &:checked + label {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n\n // Show tabbed block content\n + .tabbed-content {\n display: block;\n }\n }\n\n // Tab label on focus\n &:focus + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) + label {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n // Tab label\n > label {\n z-index: 1;\n width: auto;\n padding: px2em(12px, 12.8px) 1.25em px2em(10px, 12.8px);\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: px2rem(12.8px);\n border-bottom: px2rem(2px) solid transparent;\n cursor: pointer;\n transition: color 250ms;\n\n // Tab label on hover\n &:hover {\n color: var(--md-accent-fg-color);\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-tasklist-icon:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n --md-tasklist-icon--checked:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Tasklist item\n .task-list-item {\n position: relative;\n list-style-type: none;\n\n // Make checkbox items align with normal list items, but position\n // everything in ems for correct layout at smaller font sizes\n [type=\"checkbox\"] {\n position: absolute;\n top: 0.45em;\n left: -2em;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: -2em;\n left: initial;\n }\n }\n }\n\n // Hide native checkbox, when custom classes are enabled\n .task-list-control [type=\"checkbox\"] {\n z-index: -1;\n opacity: 0;\n }\n\n // Tasklist indicator in unchecked state\n .task-list-indicator::before {\n position: absolute;\n top: 0.15em;\n left: px2em(-24px);\n width: px2em(20px);\n height: px2em(20px);\n background-color: var(--md-default-fg-color--lightest);\n mask-image: var(--md-tasklist-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2em(-24px);\n left: initial;\n }\n }\n\n // Tasklist indicator in checked state\n [type=\"checkbox\"]:checked + .task-list-indicator::before {\n background-color: $clr-green-a400;\n mask-image: var(--md-tasklist-icon--checked);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // [tablet +]: Allow for rendering content as sidebars\n @include break-from-device(tablet) {\n\n // Modifier to float block elements\n .inline {\n float: left;\n width: px2rem(234px);\n margin-top: 0;\n margin-right: px2rem(16px);\n margin-bottom: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: right;\n margin-right: 0;\n margin-left: px2rem(16px);\n }\n\n // Modifier to move to end (ltr: right, rtl: left)\n &.end {\n float: right;\n margin-right: 0;\n margin-left: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n margin-right: px2rem(16px);\n margin-left: 0;\n }\n }\n }\n }\n}\n"]} \ No newline at end of file diff --git a/assets/stylesheets/palette.3f5d1f46.min.css b/assets/stylesheets/palette.3f5d1f46.min.css new file mode 100644 index 0000000..8fdf1b2 --- /dev/null +++ b/assets/stylesheets/palette.3f5d1f46.min.css @@ -0,0 +1,2 @@ +[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=indigo]{--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:hsla(0,0%,100%,0.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,0.7);--md-primary-fg-color--dark:rgba(0,0,0,0.07);--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54);--md-typeset-a-color:#4051b5}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,0.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}}@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,0.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--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-mark-color:rgba(66,135,255,0.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-bg-color:hsla(var(--md-hue),0%,100%,0.025);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1)}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#5d6cc0}} +/*# sourceMappingURL=palette.3f5d1f46.min.css.map */ \ No newline at end of file diff --git a/assets/stylesheets/palette.3f5d1f46.min.css.map b/assets/stylesheets/palette.3f5d1f46.min.css.map new file mode 100644 index 0000000..9f09ef0 --- /dev/null +++ b/assets/stylesheets/palette.3f5d1f46.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/palette/_accent.scss","src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss","src/assets/stylesheets/palette/_scheme.scss"],"names":[],"mappings":"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","file":"src/assets/stylesheets/palette.scss","sourcesContent":["////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n@each $name, $color in (\n \"red\": $clr-red-a400,\n \"pink\": $clr-pink-a400,\n \"purple\": $clr-purple-a200,\n \"deep-purple\": $clr-deep-purple-a200,\n \"indigo\": $clr-indigo-a200,\n \"blue\": $clr-blue-a200,\n \"light-blue\": $clr-light-blue-a700,\n \"cyan\": $clr-cyan-a700,\n \"teal\": $clr-teal-a700,\n \"green\": $clr-green-a700,\n \"light-green\": $clr-light-green-a700,\n \"lime\": $clr-lime-a700,\n \"yellow\": $clr-yellow-a700,\n \"amber\": $clr-amber-a700,\n \"orange\": $clr-orange-a400,\n \"deep-orange\": $clr-deep-orange-a200\n) {\n\n // Color palette\n [data-md-color-accent=\"#{$name}\"] {\n --md-accent-fg-color: hsla(#{hex2hsl($color)}, 1);\n --md-accent-fg-color--transparent: hsla(#{hex2hsl($color)}, 0.1);\n\n // Inverted text for lighter shades\n @if index(\"lime\" \"yellow\" \"amber\" \"orange\", $name) {\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n } @else {\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n }\n }\n}\n","[data-md-color-accent=red] {\n --md-accent-fg-color: hsla(348, 100%, 55%, 1);\n --md-accent-fg-color--transparent: hsla(348, 100%, 55%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=pink] {\n --md-accent-fg-color: hsla(339, 100%, 48%, 1);\n --md-accent-fg-color--transparent: hsla(339, 100%, 48%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=purple] {\n --md-accent-fg-color: hsla(291, 96%, 62%, 1);\n --md-accent-fg-color--transparent: hsla(291, 96%, 62%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=deep-purple] {\n --md-accent-fg-color: hsla(256, 100%, 65%, 1);\n --md-accent-fg-color--transparent: hsla(256, 100%, 65%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=indigo] {\n --md-accent-fg-color: hsla(231, 99%, 66%, 1);\n --md-accent-fg-color--transparent: hsla(231, 99%, 66%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=blue] {\n --md-accent-fg-color: hsla(218, 100%, 63%, 1);\n --md-accent-fg-color--transparent: hsla(218, 100%, 63%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=light-blue] {\n --md-accent-fg-color: hsla(203, 100%, 46%, 1);\n --md-accent-fg-color--transparent: hsla(203, 100%, 46%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=cyan] {\n --md-accent-fg-color: hsla(188, 100%, 42%, 1);\n --md-accent-fg-color--transparent: hsla(188, 100%, 42%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=teal] {\n --md-accent-fg-color: hsla(172, 100%, 37%, 1);\n --md-accent-fg-color--transparent: hsla(172, 100%, 37%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=green] {\n --md-accent-fg-color: hsla(145, 100%, 39%, 1);\n --md-accent-fg-color--transparent: hsla(145, 100%, 39%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=light-green] {\n --md-accent-fg-color: hsla(97, 81%, 48%, 1);\n --md-accent-fg-color--transparent: hsla(97, 81%, 48%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=lime] {\n --md-accent-fg-color: hsla(75, 100%, 46%, 1);\n --md-accent-fg-color--transparent: hsla(75, 100%, 46%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=yellow] {\n --md-accent-fg-color: hsla(50, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(50, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=amber] {\n --md-accent-fg-color: hsla(40, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(40, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=orange] {\n --md-accent-fg-color: hsla(34, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(34, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=deep-orange] {\n --md-accent-fg-color: hsla(14, 100%, 63%, 1);\n --md-accent-fg-color--transparent: hsla(14, 100%, 63%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=red] {\n --md-primary-fg-color: hsla(1, 83%, 63%, 1);\n --md-primary-fg-color--light: hsla(0, 69%, 67%, 1);\n --md-primary-fg-color--dark: hsla(1, 77%, 55%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=pink] {\n --md-primary-fg-color: hsla(340, 82%, 52%, 1);\n --md-primary-fg-color--light: hsla(340, 82%, 59%, 1);\n --md-primary-fg-color--dark: hsla(336, 78%, 43%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=purple] {\n --md-primary-fg-color: hsla(291, 47%, 51%, 1);\n --md-primary-fg-color--light: hsla(291, 47%, 60%, 1);\n --md-primary-fg-color--dark: hsla(287, 65%, 40%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=deep-purple] {\n --md-primary-fg-color: hsla(262, 47%, 55%, 1);\n --md-primary-fg-color--light: hsla(262, 47%, 63%, 1);\n --md-primary-fg-color--dark: hsla(262, 52%, 47%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=indigo] {\n --md-primary-fg-color: hsla(231, 48%, 48%, 1);\n --md-primary-fg-color--light: hsla(231, 44%, 56%, 1);\n --md-primary-fg-color--dark: hsla(232, 54%, 41%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=blue] {\n --md-primary-fg-color: hsla(207, 90%, 54%, 1);\n --md-primary-fg-color--light: hsla(207, 90%, 61%, 1);\n --md-primary-fg-color--dark: hsla(210, 79%, 46%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=light-blue] {\n --md-primary-fg-color: hsla(199, 98%, 48%, 1);\n --md-primary-fg-color--light: hsla(199, 92%, 56%, 1);\n --md-primary-fg-color--dark: hsla(201, 98%, 41%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=cyan] {\n --md-primary-fg-color: hsla(187, 100%, 42%, 1);\n --md-primary-fg-color--light: hsla(187, 71%, 50%, 1);\n --md-primary-fg-color--dark: hsla(186, 100%, 33%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=teal] {\n --md-primary-fg-color: hsla(174, 100%, 29%, 1);\n --md-primary-fg-color--light: hsla(174, 63%, 40%, 1);\n --md-primary-fg-color--dark: hsla(173, 100%, 24%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=green] {\n --md-primary-fg-color: hsla(122, 39%, 49%, 1);\n --md-primary-fg-color--light: hsla(123, 38%, 57%, 1);\n --md-primary-fg-color--dark: hsla(123, 43%, 39%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=light-green] {\n --md-primary-fg-color: hsla(88, 50%, 53%, 1);\n --md-primary-fg-color--light: hsla(88, 50%, 60%, 1);\n --md-primary-fg-color--dark: hsla(92, 48%, 42%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=lime] {\n --md-primary-fg-color: hsla(66, 70%, 54%, 1);\n --md-primary-fg-color--light: hsla(66, 70%, 61%, 1);\n --md-primary-fg-color--dark: hsla(62, 61%, 44%, 1);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=yellow] {\n --md-primary-fg-color: hsla(54, 100%, 62%, 1);\n --md-primary-fg-color--light: hsla(54, 100%, 67%, 1);\n --md-primary-fg-color--dark: hsla(43, 96%, 58%, 1);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=amber] {\n --md-primary-fg-color: hsla(45, 100%, 51%, 1);\n --md-primary-fg-color--light: hsla(45, 100%, 58%, 1);\n --md-primary-fg-color--dark: hsla(38, 100%, 50%, 1);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=orange] {\n --md-primary-fg-color: hsla(36, 100%, 57%, 1);\n --md-primary-fg-color--light: hsla(36, 100%, 57%, 1);\n --md-primary-fg-color--dark: hsla(33, 100%, 49%, 1);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=deep-orange] {\n --md-primary-fg-color: hsla(14, 100%, 63%, 1);\n --md-primary-fg-color--light: hsla(14, 100%, 70%, 1);\n --md-primary-fg-color--dark: hsla(14, 91%, 54%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=brown] {\n --md-primary-fg-color: hsla(16, 25%, 38%, 1);\n --md-primary-fg-color--light: hsla(16, 18%, 47%, 1);\n --md-primary-fg-color--dark: hsla(14, 26%, 29%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=grey] {\n --md-primary-fg-color: hsla(0, 0%, 46%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 62%, 1);\n --md-primary-fg-color--dark: hsla(0, 0%, 38%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=blue-grey] {\n --md-primary-fg-color: hsla(199, 18%, 40%, 1);\n --md-primary-fg-color--light: hsla(200, 18%, 46%, 1);\n --md-primary-fg-color--dark: hsla(199, 18%, 33%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=white] {\n --md-primary-fg-color: hsla(0, 0%, 100%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.07);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-typeset-a-color: hsla(231, 48%, 48%, 1);\n}\n@media screen and (min-width: 60em) {\n [data-md-color-primary=white] .md-search__form {\n background-color: rgba(0, 0, 0, 0.07);\n }\n [data-md-color-primary=white] .md-search__form:hover {\n background-color: rgba(0, 0, 0, 0.32);\n }\n [data-md-color-primary=white] .md-search__input + .md-search__icon {\n color: rgba(0, 0, 0, 0.87);\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-color-primary=white] .md-tabs {\n border-bottom: 0.05rem solid rgba(0, 0, 0, 0.07);\n }\n}\n\n[data-md-color-primary=black] {\n --md-primary-fg-color: hsla(0, 0%, 0%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-typeset-a-color: hsla(231, 48%, 48%, 1);\n}\n[data-md-color-primary=black] .md-header {\n background-color: black;\n}\n@media screen and (max-width: 59.9375em) {\n [data-md-color-primary=black] .md-nav__source {\n background-color: rgba(0, 0, 0, 0.87);\n }\n}\n@media screen and (min-width: 60em) {\n [data-md-color-primary=black] .md-search__form {\n background-color: rgba(255, 255, 255, 0.12);\n }\n [data-md-color-primary=black] .md-search__form:hover {\n background-color: rgba(255, 255, 255, 0.3);\n }\n}\n@media screen and (max-width: 76.1875em) {\n html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer] {\n background-color: black;\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-color-primary=black] .md-tabs {\n background-color: black;\n }\n}\n\n@media screen {\n [data-md-color-scheme=slate] {\n --md-hue: 232;\n --md-default-fg-color: hsla(var(--md-hue), 75%, 95%, 1);\n --md-default-fg-color--light: hsla(var(--md-hue), 75%, 90%, 0.62);\n --md-default-fg-color--lighter: hsla(var(--md-hue), 75%, 90%, 0.32);\n --md-default-fg-color--lightest: hsla(var(--md-hue), 75%, 90%, 0.12);\n --md-default-bg-color: hsla(var(--md-hue), 15%, 21%, 1);\n --md-default-bg-color--light: hsla(var(--md-hue), 15%, 21%, 0.54);\n --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 21%, 0.26);\n --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 21%, 0.07);\n --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 1);\n --md-code-bg-color: hsla(var(--md-hue), 15%, 15%, 1);\n --md-code-hl-color: hsla(218, 100%, 63%, 0.15);\n --md-code-hl-number-color: hsla(6, 74%, 63%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 66%, 1);\n --md-code-hl-function-color: hsla(291, 57%, 65%, 1);\n --md-code-hl-constant-color: hsla(250, 62%, 70%, 1);\n --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1);\n --md-code-hl-string-color: hsla(150, 58%, 44%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n --md-typeset-color: var(--md-default-fg-color);\n --md-typeset-a-color: var(--md-primary-fg-color);\n --md-typeset-mark-color: hsla(218, 100%, 63%, 0.3);\n --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 94%, 0.12);\n --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 94%, 0.2);\n --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1);\n --md-typeset-table-color: hsla(var(--md-hue), 75%, 95%, 0.12);\n --md-admonition-bg-color: hsla(var(--md-hue), 0%, 100%, 0.025);\n --md-footer-bg-color: hsla(var(--md-hue), 15%, 12%, 0.87);\n --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 10%, 1);\n }\n [data-md-color-scheme=slate][data-md-color-primary=black], [data-md-color-scheme=slate][data-md-color-primary=white] {\n --md-typeset-a-color: hsla(231, 44%, 56%, 1);\n }\n}\n\n/*# sourceMappingURL=palette.css.map */","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n@each $name, $colors in (\n \"red\": $clr-red-400 $clr-red-300 $clr-red-600,\n \"pink\": $clr-pink-500 $clr-pink-400 $clr-pink-700,\n \"purple\": $clr-purple-400 $clr-purple-300 $clr-purple-600,\n \"deep-purple\": $clr-deep-purple-400 $clr-deep-purple-300 $clr-deep-purple-500,\n \"indigo\": $clr-indigo-500 $clr-indigo-400 $clr-indigo-700,\n \"blue\": $clr-blue-500 $clr-blue-400 $clr-blue-700,\n \"light-blue\": $clr-light-blue-500 $clr-light-blue-400 $clr-light-blue-700,\n \"cyan\": $clr-cyan-500 $clr-cyan-400 $clr-cyan-700,\n \"teal\": $clr-teal-500 $clr-teal-400 $clr-teal-700,\n \"green\": $clr-green-500 $clr-green-400 $clr-green-700,\n \"light-green\": $clr-light-green-500 $clr-light-green-400 $clr-light-green-700,\n \"lime\": $clr-lime-500 $clr-lime-400 $clr-lime-700,\n \"yellow\": $clr-yellow-500 $clr-yellow-400 $clr-yellow-700,\n \"amber\": $clr-amber-500 $clr-amber-400 $clr-amber-700,\n \"orange\": $clr-orange-400 $clr-orange-400 $clr-orange-600,\n \"deep-orange\": $clr-deep-orange-400 $clr-deep-orange-300 $clr-deep-orange-600,\n \"brown\": $clr-brown-500 $clr-brown-400 $clr-brown-700,\n \"grey\": $clr-grey-600 $clr-grey-500 $clr-grey-700,\n \"blue-grey\": $clr-blue-grey-600 $clr-blue-grey-500 $clr-blue-grey-700\n) {\n\n // Color palette\n [data-md-color-primary=\"#{$name}\"] {\n --md-primary-fg-color: hsla(#{hex2hsl(nth($colors, 1))}, 1);\n --md-primary-fg-color--light: hsla(#{hex2hsl(nth($colors, 2))}, 1);\n --md-primary-fg-color--dark: hsla(#{hex2hsl(nth($colors, 3))}, 1);\n\n // Inverted text for lighter shades\n @if index(\"lime\" \"yellow\" \"amber\" \"orange\", $name) {\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n } @else {\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: white\n// ----------------------------------------------------------------------------\n\n// Color palette\n[data-md-color-primary=\"white\"] {\n --md-primary-fg-color: hsla(0, 0%, 100%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.07);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n\n // Typeset color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n\n // [tablet portrait +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n\n // Search form\n .md-search__form {\n background-color: hsla(0, 0%, 0%, 0.07);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 0%, 0.32);\n }\n }\n\n // Search icon\n .md-search__input + .md-search__icon {\n color: hsla(0, 0%, 0%, 0.87);\n }\n }\n\n // [screen +]: Add bottom border for tabs\n @include break-from-device(screen) {\n\n // Navigation tabs\n .md-tabs {\n border-bottom: px2rem(1px) solid hsla(0, 0%, 0%, 0.07);\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: black\n// ----------------------------------------------------------------------------\n\n// Color palette\n[data-md-color-primary=\"black\"] {\n --md-primary-fg-color: hsla(0, 0%, 0%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Text color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n\n // Header\n .md-header {\n background-color: hsla(0, 0%, 0%, 1);\n }\n\n // [tablet portrait -]: Layered navigation\n @include break-to-device(tablet portrait) {\n\n // Repository information container\n .md-nav__source {\n background-color: hsla(0, 0%, 0%, 0.87);\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n\n // Search form\n .md-search__form {\n background-color: hsla(0, 0%, 100%, 0.12);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 100%, 0.3);\n }\n }\n }\n\n // [tablet -]: Layered navigation\n @include break-to-device(tablet) {\n\n // Site title in main navigation\n html & .md-nav--primary .md-nav__title[for=\"__drawer\"] {\n background-color: hsla(0, 0%, 0%, 1);\n }\n }\n\n // [screen +]: Set background color for tabs\n @include break-from-device(screen) {\n\n // Navigation tabs\n .md-tabs {\n background-color: hsla(0, 0%, 0%, 1);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n///\n/// Device-specific breakpoints\n///\n/// @example\n/// $break-devices: (\n/// mobile: (\n/// portrait: 220px 479px,\n/// landscape: 480px 719px\n/// ),\n/// tablet: (\n/// portrait: 720px 959px,\n/// landscape: 960px 1219px\n/// ),\n/// screen: (\n/// small: 1220px 1599px,\n/// medium: 1600px 1999px,\n/// large: 2000px\n/// )\n/// );\n///\n$break-devices: () !default;\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n///\n/// Choose minimum and maximum device widths\n///\n@function break-select-min-max($devices) {\n $min: 1000000;\n $max: 0;\n @each $key, $value in $devices {\n @while type-of($value) == map {\n $value: break-select-min-max($value);\n }\n @if type-of($value) == list {\n @each $number in $value {\n @if type-of($number) == number {\n $min: min($number, $min);\n @if $max {\n $max: max($number, $max);\n }\n } @else {\n @error \"Invalid number: #{$number}\";\n }\n }\n } @else if type-of($value) == number {\n $min: min($value, $min);\n $max: null;\n } @else {\n @error \"Invalid value: #{$value}\";\n }\n }\n @return $min, $max;\n}\n\n///\n/// Select minimum and maximum widths for a device breakpoint\n///\n@function break-select-device($device) {\n $current: $break-devices;\n @for $n from 1 through length($device) {\n @if type-of($current) == map {\n $current: map-get($current, nth($device, $n));\n } @else {\n @error \"Invalid device map: #{$devices}\";\n }\n }\n @if type-of($current) == list or type-of($current) == number {\n $current: (default: $current);\n }\n @return break-select-min-max($current);\n}\n\n// ----------------------------------------------------------------------------\n// Mixins\n// ----------------------------------------------------------------------------\n\n///\n/// A minimum-maximum media query breakpoint\n///\n@mixin break-at($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (min-width: $breakpoint) {\n @content;\n }\n } @else if type-of($breakpoint) == list {\n $min: nth($breakpoint, 1);\n $max: nth($breakpoint, 2);\n @if type-of($min) == number and type-of($max) == number {\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// An orientation media query breakpoint\n///\n@mixin break-at-orientation($breakpoint) {\n @if type-of($breakpoint) == string {\n @media screen and (orientation: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A maximum-aspect-ratio media query breakpoint\n///\n@mixin break-at-ratio($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (max-aspect-ratio: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A minimum-maximum media query device breakpoint\n///\n@mixin break-at-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n @if nth($breakpoint, 2) {\n $min: nth($breakpoint, 1);\n $max: nth($breakpoint, 2);\n\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A minimum media query device breakpoint\n///\n@mixin break-from-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $min: nth($breakpoint, 1);\n\n @media screen and (min-width: $min) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A maximum media query device breakpoint\n///\n@mixin break-to-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $max: nth($breakpoint, 2);\n\n @media screen and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Only use dark mode on screens\n@media screen {\n\n // Slate theme, i.e. dark mode\n [data-md-color-scheme=\"slate\"] {\n\n // Slate's hue in the range [0,360] - change this variable to alter the tone\n // of the theme, e.g. to make it more redish or greenish. This is a slate-\n // specific variable, but the same approach may be adapted to custom themes.\n --md-hue: 232;\n\n // Default color shades\n --md-default-fg-color: hsla(var(--md-hue), 75%, 95%, 1);\n --md-default-fg-color--light: hsla(var(--md-hue), 75%, 90%, 0.62);\n --md-default-fg-color--lighter: hsla(var(--md-hue), 75%, 90%, 0.32);\n --md-default-fg-color--lightest: hsla(var(--md-hue), 75%, 90%, 0.12);\n --md-default-bg-color: hsla(var(--md-hue), 15%, 21%, 1);\n --md-default-bg-color--light: hsla(var(--md-hue), 15%, 21%, 0.54);\n --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 21%, 0.26);\n --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 21%, 0.07);\n\n // Code color shades\n --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 1);\n --md-code-bg-color: hsla(var(--md-hue), 15%, 15%, 1);\n\n // Code highlighting color shades\n --md-code-hl-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.15);\n --md-code-hl-number-color: hsla(6, 74%, 63%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 66%, 1);\n --md-code-hl-function-color: hsla(291, 57%, 65%, 1);\n --md-code-hl-constant-color: hsla(250, 62%, 70%, 1);\n --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1);\n --md-code-hl-string-color: hsla(150, 58%, 44%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n\n // Typeset color shades\n --md-typeset-color: var(--md-default-fg-color);\n\n // Typeset `a` color shades\n --md-typeset-a-color: var(--md-primary-fg-color);\n\n // Typeset `mark` color shades\n --md-typeset-mark-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.3);\n\n // Typeset `kbd` color shades\n --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 94%, 0.12);\n --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 94%, 0.2);\n --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1);\n\n // Typeset `table` color shades\n --md-typeset-table-color: hsla(var(--md-hue), 75%, 95%, 0.12);\n\n // Admonition color shades\n --md-admonition-bg-color: hsla(var(--md-hue), 0%, 100%, 0.025);\n\n // Footer color shades\n --md-footer-bg-color: hsla(var(--md-hue), 15%, 12%, 0.87);\n --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 10%, 1);\n\n // Black and white primary colors\n &[data-md-color-primary=\"black\"],\n &[data-md-color-primary=\"white\"] {\n\n // Typeset color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-400)}, 1);\n }\n }\n}\n"]} \ No newline at end of file diff --git a/best-models-on-imagenet/index.html b/best-models-on-imagenet/index.html new file mode 100644 index 0000000..1421787 --- /dev/null +++ b/best-models-on-imagenet/index.html @@ -0,0 +1,1519 @@ + + + + + + + + + + + + + + + + + + + + + + + 在 ImageNet 上表现出色的经典模型 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    在 ImageNet 上表现出色的经典模型

    +

    ImageNet 是由李飞飞主导建立的一个超大的计算机视觉数据集。基于此数据集,自 2010 年至 2017 年举办 ImageNet 挑战赛,即 ImageNet Large Scale Visual Recognition Challenge (ILSVRC)。这篇文章以时间顺序记录了在 ImageNet 上表现出色的模型,很多也是 ILSVRC 上的冠军。

    +

    预训练模型使用方法

    +

    TensorFlow

    + +

    PyTorch

    + +

    模型论文

    +

    参考链接:https://paperswithcode.com/sota/image-classification-on-imagenet

    +

    VGG

    +

    Very Deep Convolutional Networks for Large-Scale Image Recognition
    +https://arxiv.org/abs/1409.1556
    +Submitted on 4 Sep 2014

    +

    ResNet

    +

    Deep Residual Learning for Image Recognition
    +https://arxiv.org/abs/1512.03385
    +Submitted on 10 Dec 2015

    +

    InceptionV3

    +

    Rethinking the Inception Architecture for Computer Vision
    +https://arxiv.org/abs/1512.00567
    +Submitted on 2 Dec 2015

    +

    InceptionResNetV2

    +

    Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning
    +https://arxiv.org/abs/1602.07261
    +Submitted on 23 Feb 2016

    +

    DenseNet

    +

    Densely Connected Convolutional Networks
    +https://arxiv.org/abs/1608.06993
    +Submitted on 25 Aug 2016

    +

    Xception

    +

    Xception: Deep Learning with Depthwise Separable Convolutions
    +https://arxiv.org/abs/1610.02357
    +Submitted on 7 Oct 2016

    +

    NASNet

    +

    Neural Architecture Search with Reinforcement Learning
    +https://arxiv.org/abs/1611.01578
    +Submitted on 5 Nov 2016

    +

    EfficientNet

    +

    EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks
    +https://arxiv.org/abs/1905.11946
    +Submitted on 28 May 2019

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cv-dataset/index.html b/cv-dataset/index.html new file mode 100644 index 0000000..2d7af99 --- /dev/null +++ b/cv-dataset/index.html @@ -0,0 +1,1426 @@ + + + + + + + + + + + + + + + + + + + + + + + 常用 CV 数据集 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    常用 CV 数据集

    +

    计算机视觉方面常用的数据集。

    +

    数据集使用方法

    +

    TensorFlow

    + +

    PyTorch

    + +

    MNIST

    +

    MNISTsamples

    +

    MNIST 是一个手写数字数据集,训练集60000张,测试集 10000张,共有 10 个类别,图像是尺寸为 (28, 28) 的黑白图。

    +

    CIFAR

    +

    CIFAR-10samples

    +

    CIFAR-10 是一个彩色图像数据集,训练集 60000张,测试集 10000张,共有 10 个类别,图像是尺寸为 (32, 32) 的彩图。

    +

    此外还有 CIFAR-100 数据集,训练集有 60000张,测试集 10000张,共有 100个类别,图像也是 (32, 32) 的彩图。

    +

    ImageNet

    +

    +

    ImageNet 是一个把深度学习推向一个新的高度的数据集,非常重要。

    +

    ImageNet 2012 训练集共有约 120万张图像,验证集有 50000张,图像尺寸各不相同,在使用的时候通常会经过缩放和随机裁剪处理为相同尺寸的正方形图片。

    +

    VGG、ResNet 和 DenseNet 的默认图像尺寸为 224,Inception 是 299 ,NASNet 是 331,最新的 EfficientNet 使用了从 224 到 600 的不同尺寸。尺寸越大的同时也会使精度越高。

    +

    VOC

    +

    VOCsamples

    +

    VOC 的全称是 The PASCAL Visual Object Classes Challenge,该数据集的标注很丰富,可以用于检测和分割等任务。该数据集共有 20个类别。在 YOLOv3 的训练中,使用了 VOC 2007 到 VOC 2012 的所有数据。

    +

    VOC 2007 有 9963 张图像,其中训练集 2501 张,验证集2510 张,测试集 4952 张。

    +

    COCO

    +

    +

    COCO 全称是 Common Objects in Context,是一个大规模检测、分割、关键点和看图说话数据集。数据集有 80 个类别。

    +

    COCO 2014 训练集有 83k 张图,验证集有 41k,测试集有 41k。
    +COCO 2015 测试集有 81k。
    +COCO 2017 训练集有 118k ,验证集有 5k,测试集有 41k。

    +

    CelebA

    +

    +

    CelebA 全称是 Large-scale CelebFaces Attributes (CelebA) Dataset,意思是大规模名人面部属性数据集。数据集共有 202599张图,10117位名人,属性有头发、眉毛、眼睛、鼻子、嘴巴、表情和性别等40种属性。此数据集可以用来做人脸识别(分类)、人脸检测、人脸关键点检测、人脸 GAN 等任务。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cv-resources/cnn.jpg b/cv-resources/cnn.jpg new file mode 100644 index 0000000..7d9e865 Binary files /dev/null and b/cv-resources/cnn.jpg differ diff --git a/cv-resources/d2l.jpg b/cv-resources/d2l.jpg new file mode 100644 index 0000000..ce698ea Binary files /dev/null and b/cv-resources/d2l.jpg differ diff --git a/cv-resources/dl-cv.jpg b/cv-resources/dl-cv.jpg new file mode 100644 index 0000000..5050373 Binary files /dev/null and b/cv-resources/dl-cv.jpg differ diff --git a/cv-resources/index.html b/cv-resources/index.html new file mode 100644 index 0000000..b9c31f2 --- /dev/null +++ b/cv-resources/index.html @@ -0,0 +1,1531 @@ + + + + + + + + + + + + + + + + + + + + + + + CV 学习资源 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    CV 学习资源

    +

    这里记录了为我提供了非常多帮助的学习资源。

    +

    公开课

    +

    Coursera

    + +

    吴恩达的机器学习和深度学习的课程是大部分人的入门课程,当然也是我的入门课程。

    +

    如果在机器学习和深度学习方面,你是零基础或者基础十分薄弱的,那么推荐你学习这门课程,并完成里面的代码和作业任务。当你学完这门课就具有了一定的基础,可能会在更细致的领域进行研究,比如计算机视觉或者自然语言处理。

    +

    CS231n

    +

    如果你感兴趣的领域是计算机视觉,那么斯坦福大学的 CS231n 课程是不能错过的,这是我的计算机视觉入门课程,我第一次从这里学会并理解卷积的基本概念。

    +

    机器学习和深度学习的语言以 Python 为主,如果需要入门和练习 Python,这个课程中也提供了非常优秀的学习资源。

    +

    @爱可可-爱生活

    +

    @爱可可-爱生活 是北京邮电大学的老师的微博账户,每天会发布最新的论文和 GitHub 优秀项目等,可以通过它关注机器学习领域最新研究成果。

    +

    同时,它的哔哩哔哩账号 fly51fly 下收录了非常多的优秀公开课,比如斯坦福 2019 最新的自然语言理解课程。当你对知识感到饥渴时就可以来这里充电。

    +

    网站

    +

    paperswithcode

    +

    这个网站总结了当前有开源代码的论文,以及它们在各项竞赛上的表现。

    +

    比如这个页面可以查看 ImageNet 上最好的模型排名:https://paperswithcode.com/sota/image-classification-on-imagenet

    +

    书籍

    +

    机器学习

    +

    机器学习

    +
    +

    机器学习是计算机科学与人工智能的重要分支领域. 本书作为该领域的入门教材,在内容上尽可能涵盖机器学习基础知识的各方面。 为了使尽可能多的读者通过本书对机器学习有所了解, 作者试图尽可能少地使用数学知识. 然而, 少量的概率、统计、代数、优化、逻辑知识似乎不可避免. 因此, 本书更适合大学三年级以上的理工科本科生和研究生, 以及具有类似背景的对机器学 习感兴趣的人士. 为方便读者, 本书附录给出了一些相关数学基础知识简介.

    +

    全书共16 章,大致分为3 个部分:第1 部分(第1~3 章)介绍机器学习的基础知识;第2 部分(第4~10 章)讨论一些经典而常用的机器学习方法(决策树、神经网络、支持向量机、贝叶斯分类器、集成学习、聚类、降维与度量学习);第3 部分(第11~16 章)为进阶知识,内容涉及特征选择与稀疏学习、计算学习理论、半监督学习、概率图模型、规则学习以及强化学习等.前3章之外的后续各章均相对独立, 读者可根据自己的兴趣和时间情况选择使用. 根据课时情况, 一个学期的本科生课程可考虑讲授前9章或前10章; 研究生课程则不妨使用全书.

    +

    书中除第1章外, 每章都给出了十道习题. 有的习题是帮助读者巩固本章学习, 有的是为了引导读者扩展相关知识. 一学期的一般课程可使用这些习题, 再辅以两到三个针对具体数据集的大作业. 带星号的习题则有相当难度, 有些并无现成答案, 谨供富有进取心的读者启发思考.

    +

    本书可作为高等院校计算机、自动化及相关专业的本科生或研究生教材,也可供对机器学习感兴趣的研究人员和工程技术人员阅读参考。

    +
    +

    此书是我入门机器学习的时候认真看过的,对我的帮助很大,建议大家仔细阅读。

    +

    解析深度学习:卷积神经网络原理与视觉实践

    +

    解析深度学习:卷积神经网络原理与视觉实践

    +
    +

    深度学习,特别是深度卷积神经网络是人工智能的重要分支领域,卷积神经网络技术也被广泛应用于各种现实场景,在许多问题上都取得了超越人类智能的结果。本书作为该领域的入门书籍,在内容上涵盖深度卷积神经网络的基础知识和实践应用两大方面。《解析深度学习:卷积神经网络原理与视觉实践》共14 章,分为三个部分:第一部分为绪论;第二部分 (第1~4 章)介绍卷积神经网络的基础知识、基本部件、经典结构和模型压缩等基础理论内容;第三部分(第5~14 章)介绍深度卷积神经网络自数据准备开始,到模型参数初始化、不同网络部件的选择、网络配置、网络模型训练、不平衡数据处理,最终到模型集成等实践应用技巧和经验。《解析深度学习:卷积神经网络原理与视觉实践》并不是一本编程类书籍,而是希望通过“基础知识”和“实践技巧”两方面使读者从更高维度了解、掌握并成功构建针对自身应用问题的深度卷积神经网络。

    +

    《解析深度学习:卷积神经网络原理与视觉实践》可作为深度学习和卷积神经网络爱好者的入门书籍,也可供没有机器学习背景但希望能快速掌握该方面知识并将其应用于实际问题的各行从业者阅读参考。

    +
    +

    开源电子版:http://lamda.nju.edu.cn/weixs/book/CNN_book.html

    +

    此书还是电子版的时候我就已经在看了,对于入门计算机视觉方向的初学者来说概念讲得很透彻。

    +

    动手学深度学习

    +

    动手学深度学习

    +
    +

    本书旨在向读者交付有关深度学习的交互式学习体验。书中不仅阐述深度学习的算法原理,还演示它们的实现和运行。与传统图书不同,本书的每一节都是一个可以下载并运行的 Jupyter记事本,它将文字、公式、图像、代码和运行结果结合在了一起。此外,读者还可以访问并参与书中内容的讨论。

    +

    全书的内容分为3个部分:第一部分介绍深度学习的背景,提供预备知识,并包括深度学习最基础的概念和技术;第二部分描述深度学习计算的重要组成部分,还解释近年来令深度学习在多个领域大获成功的卷积神经网络和循环神经网络;第三部分评价优化算法,检验影响深度学习计算性能的重要因素,并分别列举深度学习在计算机视觉和自然语言处理中的重要应用。

    +

    本书同时覆盖深度学习的方法和实践,主要面向在校大学生、技术人员和研究人员。阅读本书需要读者了解基本的Python编程或附录中描述的线性代数、微分和概率基础。

    +
    + +

    此书还在编写的时候,我正在做一个狗分类的 Kaggle 竞赛,然后关注到 Gluon 论坛正在以 kaggle 上的排名来发放云服务代金券,于是我就参加了。然后版主问我有没有兴趣写一个 gluon 版的,我就用 gluon 写了一个,后来就在论坛和大家一起互动,学到了许多东西,成为了论坛的版主。之后此书不断完善,我也贡献了自己的一份力量。出版后,我拿到了贡献者专享的《动手学深度学习》。

    +

    如果你想使用 Gluon,这本书在合适不过了。即使你不用 Gluon,此书依然可以给你许多入门的概念,从最基础的矩阵运算,到分类、检测、分割和风格迁移等,值得一看。因为书中有大量的代码、图片、图表,建议购买全彩精装版。

    +

    深度学习技术图像处理入门

    +

    深度学习技术图像处理入门

    +
    +

    本书从机器学习、图像处理的基本概念入手,逐步阐述深度学习图像处理技术的基本原理以及简单的实现。继而以几个实战案例来介绍如何使用深度学习方法,在数据分析竞赛中取得较高的排名。最后,通过一个实战案例,介绍如何将模型放入 iOS 程序,制作相应的人工智能手机App。

    +

    本书适用于对深度学习有兴趣、希望入门这一领域的理工科大学生、研究生,以及希望了解该领域基本原理的软件开发人员。此外,本书所有案例均提供了云环境上的代码,便于读者复现结果,并进行深入学习。

    +
    +

    此书是我和胡博强一起写的,主要内容是深度学习、图像处理入门,以及几个基于 Keras 的项目。如果你关注了我的 github,那么此书是不需要买的,因为项目在 github 上都有:

    + + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cv-resources/machine-learning.jpg b/cv-resources/machine-learning.jpg new file mode 100644 index 0000000..62552c6 Binary files /dev/null and b/cv-resources/machine-learning.jpg differ diff --git a/detection-models/cascade-mask-rcnn.png b/detection-models/cascade-mask-rcnn.png new file mode 100644 index 0000000..84f2fbf Binary files /dev/null and b/detection-models/cascade-mask-rcnn.png differ diff --git a/detection-models/demo/1.jpg b/detection-models/demo/1.jpg new file mode 100644 index 0000000..117480e Binary files /dev/null and b/detection-models/demo/1.jpg differ diff --git a/detection-models/demo/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719-5bdc3824.jpg b/detection-models/demo/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719-5bdc3824.jpg new file mode 100644 index 0000000..961cb27 Binary files /dev/null and b/detection-models/demo/cascade_mask_rcnn_r50_fpn_mstrain_3x_coco_20210628_164719-5bdc3824.jpg differ diff --git a/detection-models/demo/detr_r50_8x2_150e_coco_20201130_194835-2c4b8974.jpg b/detection-models/demo/detr_r50_8x2_150e_coco_20201130_194835-2c4b8974.jpg new file mode 100644 index 0000000..22e64f0 Binary files /dev/null and b/detection-models/demo/detr_r50_8x2_150e_coco_20201130_194835-2c4b8974.jpg differ diff --git a/detection-models/demo/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.jpg b/detection-models/demo/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.jpg new file mode 100644 index 0000000..09ae13c Binary files /dev/null and b/detection-models/demo/faster_rcnn_r50_fpn_mstrain_3x_coco_20210524_110822-e10bd31c.jpg differ diff --git a/detection-models/demo/mask2former_r50_lsj_8x2_50e_coco_20220326_224516-0091ce2b.jpg b/detection-models/demo/mask2former_r50_lsj_8x2_50e_coco_20220326_224516-0091ce2b.jpg new file mode 100644 index 0000000..d52cd06 Binary files /dev/null and b/detection-models/demo/mask2former_r50_lsj_8x2_50e_coco_20220326_224516-0091ce2b.jpg differ diff --git a/detection-models/demo/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154-21b550bb.jpg b/detection-models/demo/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154-21b550bb.jpg new file mode 100644 index 0000000..36a9d16 Binary files /dev/null and b/detection-models/demo/mask_rcnn_r50_fpn_mstrain-poly_3x_coco_20210524_201154-21b550bb.jpg differ diff --git a/detection-models/demo/mask_rcnn_swin-t-p4-w7_fpn_ms-crop-3x_coco_20210906_131725-bacf6f7b.jpg b/detection-models/demo/mask_rcnn_swin-t-p4-w7_fpn_ms-crop-3x_coco_20210906_131725-bacf6f7b.jpg new file mode 100644 index 0000000..d998376 Binary files /dev/null and b/detection-models/demo/mask_rcnn_swin-t-p4-w7_fpn_ms-crop-3x_coco_20210906_131725-bacf6f7b.jpg differ diff --git a/detection-models/demo/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802-85cffbd8.jpg b/detection-models/demo/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802-85cffbd8.jpg new file mode 100644 index 0000000..6d50b49 Binary files /dev/null and b/detection-models/demo/queryinst_r50_fpn_300_proposals_crop_mstrain_480-800_3x_coco_20210904_101802-85cffbd8.jpg differ diff --git a/detection-models/demo/ssdlite_mobilenetv2_scratch_600e_coco_20210629_110627-974d9307.jpg b/detection-models/demo/ssdlite_mobilenetv2_scratch_600e_coco_20210629_110627-974d9307.jpg new file mode 100644 index 0000000..52720db Binary files /dev/null and b/detection-models/demo/ssdlite_mobilenetv2_scratch_600e_coco_20210629_110627-974d9307.jpg differ diff --git a/detection-models/demo/yolov3_d53_fp16_mstrain-608_273e_coco_20210517_213542-4bc34944.jpg b/detection-models/demo/yolov3_d53_fp16_mstrain-608_273e_coco_20210517_213542-4bc34944.jpg new file mode 100644 index 0000000..798e33b Binary files /dev/null and b/detection-models/demo/yolov3_d53_fp16_mstrain-608_273e_coco_20210517_213542-4bc34944.jpg differ diff --git a/detection-models/demo/yolov5s.jpg b/detection-models/demo/yolov5s.jpg new file mode 100644 index 0000000..865fd7f Binary files /dev/null and b/detection-models/demo/yolov5s.jpg differ diff --git a/detection-models/demo/yolov5x6.jpg b/detection-models/demo/yolov5x6.jpg new file mode 100644 index 0000000..37e72bb Binary files /dev/null and b/detection-models/demo/yolov5x6.jpg differ diff --git a/detection-models/detection-models.png b/detection-models/detection-models.png new file mode 100644 index 0000000..c0eb9b8 Binary files /dev/null and b/detection-models/detection-models.png differ diff --git a/detection-models/detr-attention.png b/detection-models/detr-attention.png new file mode 100644 index 0000000..d206322 Binary files /dev/null and b/detection-models/detr-attention.png differ diff --git a/detection-models/detr-multi-head-attention.png b/detection-models/detr-multi-head-attention.png new file mode 100644 index 0000000..84119ec Binary files /dev/null and b/detection-models/detr-multi-head-attention.png differ diff --git a/detection-models/detr-structure.png b/detection-models/detr-structure.png new file mode 100644 index 0000000..792b52d Binary files /dev/null and b/detection-models/detr-structure.png differ diff --git a/detection-models/detr-transformer.png b/detection-models/detr-transformer.png new file mode 100644 index 0000000..2125aea Binary files /dev/null and b/detection-models/detr-transformer.png differ diff --git a/detection-models/faster-rcnn-detection-head.png b/detection-models/faster-rcnn-detection-head.png new file mode 100644 index 0000000..00334d4 Binary files /dev/null and b/detection-models/faster-rcnn-detection-head.png differ diff --git a/detection-models/faster-rcnn-rpn.png b/detection-models/faster-rcnn-rpn.png new file mode 100644 index 0000000..0cc1aa0 Binary files /dev/null and b/detection-models/faster-rcnn-rpn.png differ diff --git a/detection-models/index.html b/detection-models/index.html new file mode 100644 index 0000000..1d66685 --- /dev/null +++ b/detection-models/index.html @@ -0,0 +1,1601 @@ + + + + + + + + + + + + + + + + + + + + + + + 检测模型 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + + + + + + + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    检测模型

    +

    模型概览

    +

    目标检测模型

    +

    下面几个模型是比较经典的检测模型:

    +
      +
    • 【1】SSD 2015——经典的 OneStage 模型
    • +
    • 【2】Faster R-CNN 2015——经典的 TwoStage 模型
    • +
    • 【3】YOLO v3 2018——速度较快的检测模型
    • +
    • 【4】CenterNet 2019——AnchorFree 模型
    • +
    • 【5】DETR 2020——使用 Transformer 做检测任务的模型
    • +
    • 【6】YOLO v5 2020——速度较快的检测模型
    • +
    +

    它们在 COCO2017 上的分数如下:

    +

    +

    实例分割模型

    +

    下面几个模型是比较经典的实例分割模型:

    +
      +
    • 【1】Mask R-CNN 2017——现代化的实例分割模型
    • +
    • 【2】Cascade Mask R-CNN 2019——级联的 Mask R-CNN
    • +
    • 【3】QueryInst 2021——目前排行榜第 10 名
    • +
    • 【4】SwinV2 2021——目前排行榜第 1 名
    • +
    +

    它们在 COCO2017 上的分数如下:

    +

    +

    具体模型介绍

    +

    SSD 2015

    +

    SSD: Single Shot MultiBox Detector

    +

    SSD 是 OneStage 的模型,因为没有 RPN、ROI 等操作,所以速度会快很多,代价在于精度有所降低。

    +

    YOLO 与 SSD 的结构也是类似的,不过一代的 YOLO 没有使用中间层的特征。

    +

    模型结构如下:

    +

    +

    YOLOv5 2022

    + +

    YOLOv5 仍然是属于 OneStage 模型,对结构进行了许多优化,降低了计算量。各种数据增强方法也提高了模型的精度。

    +

    +

    Faster R-CNN 2015

    +

    Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks

    +

    Faster R-CNN 是最经典的 TwoStage 模型。 使用 RPN 提取出可能是物体的区域,然后使用 ROI Pooling 抓出局部特征, 再使用分类和回归将类别和框的位置计算出来。

    +

    下图就是 FPN 结构的示意:

    +

    +

    下图是检测头的结构:

    +

    +

    DETR 2020

    +

    End-to-End Object Detection with Transformers

    +

    DETR 仍然是使用 CNN 提取特征,不过没有使用传统的 RPN 和检测 Head,因此也没有 Anchor,使用了 Transformer 直接检测物体。

    +

    DETR 结构:

    +

    +

    Transformer 结构:

    +

    +

    Multi-Head Attention 结构:

    +

    +

    Attention 结构:

    +

    +

    Mask R-CNN 2017

    +

    Mask R-CNN

    +

    经典的 TwoStage 模型,检测部分和 Faster R-CNN 一样,先提取可能是物体的部分,然后再提取这部分区域的特征计算类别和框,但是多了一个 Mask 分支,用于逐像素分类,计算该物体的 Mask。

    +

    +

    +

    Cascade Mask R-CNN 2019

    +

    Cascade R-CNN: High Quality Object Detection and Instance Segmentation

    +

    将模型的结果再输入到新的模型里做精调,反复几次,这样可以提升模型的准确率,但是也会增加计算量。

    +

    +

    模型可视化对比

    +

    为了综合评价各个模型的能力,我们使用各个模型对下图进行了推断和可视化:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    模型名称年份bbox mAP可视化图
    SSD Lite MobileNetV2201521.3
    YOLOv3201833.7
    YOLOv5s202237.4
    YOLOv5x6202255.0
    Faster R-CNN R50201540.3
    Mask R-CNN R50201740.9
    Cascade Mask R-CNN R50201944.3
    DETR R50202040.1
    Mask2Former R50202144.8
    Swin R50202146.0
    QueryInst R50202147.5
    +

    可以看到,不是 mAP 分数更高的模型就更准,目前基于 Anchor 的模型依然具备极大的优势。

    + + + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/detection-models/instance-segmentation-models.png b/detection-models/instance-segmentation-models.png new file mode 100644 index 0000000..fb4d7b4 Binary files /dev/null and b/detection-models/instance-segmentation-models.png differ diff --git a/detection-models/mask-rcnn-1.png b/detection-models/mask-rcnn-1.png new file mode 100644 index 0000000..2279d8d Binary files /dev/null and b/detection-models/mask-rcnn-1.png differ diff --git a/detection-models/mask-rcnn-2.png b/detection-models/mask-rcnn-2.png new file mode 100644 index 0000000..4e11dcd Binary files /dev/null and b/detection-models/mask-rcnn-2.png differ diff --git a/detection-models/ssd.png b/detection-models/ssd.png new file mode 100644 index 0000000..0484c8a Binary files /dev/null and b/detection-models/ssd.png differ diff --git a/detection-models/yolov5.png b/detection-models/yolov5.png new file mode 100644 index 0000000..d7fe98a Binary files /dev/null and b/detection-models/yolov5.png differ diff --git a/docker-is-good/index.html b/docker-is-good/index.html new file mode 100644 index 0000000..3168f3e --- /dev/null +++ b/docker-is-good/index.html @@ -0,0 +1,1243 @@ + + + + + + + + + + + + + + + + + + + + + + + Docker 是个好东西 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    Docker 是个好东西

    +
      +
    • 什么是 Docker
    • +
    • 安装 Docker
    • +
    • 安装 nvidia-docker
    • +
    • 如何编写 Dockerfile
    • +
    • 如何编译一个 Docker 镜像
    • +
    • 如何运行 Docker
    • +
    +

    什么是 Docker

    +

    https://docs.docker.com/

    +

    Docker 可以让你把整个应用打包成一个文件,它包含你安装的各种依赖环境,比如 CUDA、cuDNN、TensorFlow 等。其他人可以直接使用 Docker 直接运行你打包的这个镜像,不需要进行繁琐的环境配置。

    +

    Docker 的优点:

    +
      +
    • 灵活,不管你的应用环境有多复杂,都可以打包成一个镜像
    • +
    • 便携,只需要打包一次,就可以部署到任何地方运行
    • +
    • 高效,与宿主机共享操作系统内核,效率很高
    • +
    • 安全,不同的容器之间互不干扰,崩了不影响其他应用
    • +
    +

    在没有 Docker 之前,运维需要学会配置各种环境、驱动,解决各种库之间的依赖关系,现在只需要装好必要的驱动,然后运行 Docker 就好,非常方便。

    +

    安装 Docker

    +

    https://docs.docker.com/install/linux/docker-ce/ubuntu/

    +

    按照官网上的教程安装即可,下面是我运行的命令:

    +
    curl -fsSL https://get.docker.com -o get-docker.sh
    +sudo sh get-docker.sh
    +
    + +

    为了避免每次使用 docker 命令都要加 sudo,你可以执行下面的命令:

    +
    sudo usermod -aG docker $USER
    +
    + +

    添加以后,你需要重新登录机器才能生效。

    +

    你可以运行下面的命令测试 docker:

    +
    docker run hello-world
    +
    + +

    期望输出:

    +
    Hello from Docker!
    +This message shows that your installation appears to be working correctly.
    +
    +To generate this message, Docker took the following steps:
    + 1. The Docker client contacted the Docker daemon.
    + 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    +    (amd64)
    + 3. The Docker daemon created a new container from that image which runs the
    +    executable that produces the output you are currently reading.
    + 4. The Docker daemon streamed that output to the Docker client, which sent it
    +    to your terminal.
    +
    +To try something more ambitious, you can run an Ubuntu container with:
    + $ docker run -it ubuntu bash
    +
    +Share images, automate workflows, and more with a free Docker ID:
    + https://hub.docker.com/
    +
    +For more examples and ideas, visit:
    + https://docs.docker.com/get-started/
    +
    + +

    如果出现了权限问题,你可以使用下面的命令重新构建 docker 的文件系统:

    +
    sudo service docker stop
    +sudo rm -rf /var/lib/docker
    +sudo service docker start
    +
    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/how-to-build-deep-learning-workstation/4Way.jpg b/how-to-build-deep-learning-workstation/4Way.jpg new file mode 100644 index 0000000..b032edb Binary files /dev/null and b/how-to-build-deep-learning-workstation/4Way.jpg differ diff --git a/how-to-build-deep-learning-workstation/air540.png b/how-to-build-deep-learning-workstation/air540.png new file mode 100644 index 0000000..4012a7e Binary files /dev/null and b/how-to-build-deep-learning-workstation/air540.png differ diff --git a/how-to-build-deep-learning-workstation/fan1.jpg b/how-to-build-deep-learning-workstation/fan1.jpg new file mode 100644 index 0000000..1016aff Binary files /dev/null and b/how-to-build-deep-learning-workstation/fan1.jpg differ diff --git a/how-to-build-deep-learning-workstation/fan2.jpg b/how-to-build-deep-learning-workstation/fan2.jpg new file mode 100644 index 0000000..a7d16ef Binary files /dev/null and b/how-to-build-deep-learning-workstation/fan2.jpg differ diff --git a/how-to-build-deep-learning-workstation/gpu.png b/how-to-build-deep-learning-workstation/gpu.png new file mode 100644 index 0000000..8c7b767 Binary files /dev/null and b/how-to-build-deep-learning-workstation/gpu.png differ diff --git a/how-to-build-deep-learning-workstation/gpu2.png b/how-to-build-deep-learning-workstation/gpu2.png new file mode 100644 index 0000000..b9d0eda Binary files /dev/null and b/how-to-build-deep-learning-workstation/gpu2.png differ diff --git a/how-to-build-deep-learning-workstation/index.html b/how-to-build-deep-learning-workstation/index.html new file mode 100644 index 0000000..a150f6a --- /dev/null +++ b/how-to-build-deep-learning-workstation/index.html @@ -0,0 +1,1895 @@ + + + + + + + + + + + + + + + + + + + + + + + 如何配置一台深度学习工作站? - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    如何配置一台深度学习工作站?

    +

    这篇文章主要介绍的是家用的深度学习工作站,典型的配置有两种,分别是一个 GPU 的机器和 四个 GPU的机器。如果需要更多的 GPU 可以考虑配置两台四个 GPU 的机器。如果希望一台机器同时具备 8~10 个 GPU 需要联系专门的供应商进行配置,并且需要专业的机房存放这些服务器,放在家里噪声很大并且容易跳闸。

    +

    CPU

    +

    由于最近 AMD 和 Intel 频繁更新 CPU,因此大家选择新款的 CPU 比较好。

    +

    CPU 与 GPU 的关系

    +

    CPU 瓶颈没有那么大,一般以一个 GPU 对应 2~4 个 CPU 核比较好,比如单卡机器买四核 CPU,四卡机器买十核 CPU。

    +

    当你在训练的时候,只要数据生成器(DataLoader)的产出速度比 GPU 的消耗速度快,那么 CPU 就不会成为瓶颈,也就不会拖慢训练速度。

    +

    PCI-E 支持情况

    +

    除了核数,你还需要注意 PCI-E 支持情况,一般显卡是 PCI-E 4.0 x16,比如 i9-10900X 的 PCI-E 通道数是 48 ,配置四卡的话,只能支持 1x16+3x8,也就是单卡全速,三卡半速。这种情况下可以考虑选择带有 PLX 桥接芯片的主板,比如 Pro WS X299 SAGE II

    +

    英特尔CPU

    +

    英特尔 CPU 天梯图如下:

    +

    英特尔CPU

    +

    如果本文已经过时,你可以搜索关键字【CPU 天梯图】查找最新的 CPU 信息。

    +

    单卡根据预算选择合适的 CPU,双卡机器建议选 i9-10900 系列,四卡机器按照预算选 X系列 的 CPU。(注意,X 系列最新发布的 CPU 是 2019 年的,已经不建议使用)

    +

    主板

    +

    主板需要注意:

    +
      +
    • CPU 接口是否能对上,如 LGA1700 与 LGA206
    • +
    • PCI-E 插槽的高度是否够插显卡,比如 PCI-E 插口之间的距离至少要满足双槽宽显卡的高度
    • +
    • PCI-E 同时可以支持几张卡以什么样的速度运行,如 1x16 + 3x8 是常见的配置
    • +
    +

    主板必看参数

    +

    GIGABYTE X299 AORUS MASTER (rev. 1.0) 使用了 4 组 2 槽间距显卡插槽设计,支持 1x16、2x16、2x16 + 1x8、1x16 + 3x8 四种配置(需要十核以上的 CPU),这里请参阅说明书安装显卡,安装在不同位置的速度是不一样的:

    +

    GIGABYTEX299AORUSMASTER(rev.1.0)

    +

    GIGABYTEX299AORUSMASTERmanual

    +

    带有桥接芯片的主板

    +

    有的主板如 Pro WS X299 SAGE II 带有 PLX 桥接芯片,可以在 CPU 没有足够 PCI-E 的情况下达到四卡 x16 的速度:

    +

    WSX299SAGE

    +

    WSX299SAGEUserGuide

    +

    在多卡并行训练的时候,PCI-E 的传输速度决定了梯度同步的速度,如果你训练的的模型比较大,希望搭建多卡机器,建议选择支持四路 PCI-E x16 的主板。

    +

    显卡

    +

    显卡性能表

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    型号价格(元)显存(GB)性能 (TFLOPS)厚度(槽宽)
    309012,799243283
    3080Ti8,999123203
    30806,499102803
    3070Ti5,199161843
    30704,59981623
    30603,599121123
    30502,4998803
    3090涡轮15,399243282
    3080Ti涡轮10,399123202
    3080涡轮7,899102802
    3070Ti涡轮6,799161842
    3060涡轮3,899121122
    A20003,30012641
    A40006,000161531
    A450011,000201892
    A500014,500242222
    A600026,800483102
    T410,50016651
    +

    +

    训练需要 FP32 和 FP16 的性能,推断需要 INT8 的性能。训练大模型需要注意显存大小。

    +

    考虑性价比可以买 RTX 3080Ti,想要大显存比可以买 RTX 3090。

    +

    值得注意的是,官方公布的参数并不一定是最终性能,实测 A6000 是比 3090 快的:

    +

    +

    参考链接:

    + +

    涡轮与风扇

    +

    采购显卡的时候,一定要注意买涡轮版的,不要买两个或者三个风扇的版本,除非你只打算买一张卡。

    +

    因为涡轮风扇的热是往外机箱外部吹的,所以可以很好地带走热量,散热比较好。如果买三个风扇的版本,插多卡的时候,上面的卡会把热量吹向第二张卡,导致第二张卡温度过高,影响性能。

    +

    风扇显卡很有可能是超过双槽宽的,第二张卡可能插不上第二个 PCI-E 插槽,这个也需要注意。

    +

    涡轮散热

    +

    涡轮:索泰 GeForce® RTX2080-8GD6 AI版 OC HA

    +

    风扇散热

    +

    风扇:华硕 ROG 猛禽系列 GeForce RTX™ 2080 Ti OC版

    +

    硬盘

    +

    硬盘类型

    +

    常用硬盘接口有三种:

    +
      +
    • SATA3.0,速度 600MB/s
    • +
    • SAS,速度 1200MB/s
    • +
    • PCIE 3.0 x4(NVMe),速度 3.93GB/s
    • +
    • PCIE 4.0 x4(NVMe),速度 7.87GB/s
    • +
    +

    参数对比

    +

    下面是根据代表产品查询的参数:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    类型价格(元/TB)读取速度(MB/s)写入速度4K随机读取(IOPS)4K随机写入(IOPS)
    SATA3 机械硬盘150270258170550
    SATA3 固态硬盘7005605309800088000
    NVMe 固态硬盘80035003000500000480000
    +

    注:

    + +

    在面对大量小文件的时候,使用 NVMe 硬盘可以一分钟扫完 1000万文件,如果使用普通硬盘,那么就需要一天时间。为了节省生命,简化代码,硬盘建议选择 NVMe 协议的固态硬盘。

    +

    如果你的主板不够新,没有 NVMe 插槽,你可以使用 M.2 转接卡将 M.2 接口转为 PCI-E 接口。

    +

    M.2转接卡

    +

    内存

    +

    内存容量的选择通常大于显存,比如单卡配 16GB 内存,四卡配 64GB 内存。由于有数据生成器(DataLoader),数据不必全部加载到内存里,通常不会成为瓶颈。

    +

    电源

    +

    先计算功率总和,如单卡 CPU 250W,显卡 350W,加上其他的大概 200W,那么就买 850W 的电源。

    +

    双卡最好买 1200W 以上的电源,四卡最好买 2000W 的电源。如果电源不够,跑起来所有的卡以后会因为电源不足而自动关机。

    +

    一般墙上的插座只支持 220V 10A,也就是 2200W 的交流电,由于电源要把交流电转直流电,所以会有一些损耗,最高只有 2000W,因此如果想要支持八卡,最好不要在家尝试。八卡一般是四个 PDU 电源,并且电流很大,所以需要专门走线,如果在家直接从墙上接插座,然后插四个电源,容易引发火灾。

    +

    网卡

    +

    一般主板自带千兆网卡。如果需要组建多机多卡集群,请联系供应商咨询专业的解决方案。

    +

    机箱

    +

    如果配单卡,可以直接买个普通中塔机箱,注意显卡长度能放下就行。

    +

    如果配四卡机器,建议买一个全塔机箱。

    +

    下图是我搭建四卡时使用的机箱,现在已经停产了。

    +

    Air540

    +

    显示器与键盘鼠标

    +

    深度学习工作站装好系统以后就不需要显示器和键鼠套装了,装系统的时候使用手边的显示器和键盘鼠标就行。

    +

    我们一般会在深度学习机器上安装 Linux 系统,然后通过 Mac 远程连接,通过 PyCharm 远程调试,所以主机只需要插电和插网线即可,不需要连接显示器和键盘鼠标。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/how-to-build-deep-learning-workstation/intel.jpg b/how-to-build-deep-learning-workstation/intel.jpg new file mode 100644 index 0000000..d1f6363 Binary files /dev/null and b/how-to-build-deep-learning-workstation/intel.jpg differ diff --git a/how-to-build-deep-learning-workstation/m2_pcie.jpg b/how-to-build-deep-learning-workstation/m2_pcie.jpg new file mode 100644 index 0000000..1aa7ff6 Binary files /dev/null and b/how-to-build-deep-learning-workstation/m2_pcie.jpg differ diff --git a/how-to-build-deep-learning-workstation/pcie.png b/how-to-build-deep-learning-workstation/pcie.png new file mode 100644 index 0000000..4a0dd83 Binary files /dev/null and b/how-to-build-deep-learning-workstation/pcie.png differ diff --git a/how-to-build-deep-learning-workstation/pcie2.png b/how-to-build-deep-learning-workstation/pcie2.png new file mode 100644 index 0000000..4da00ff Binary files /dev/null and b/how-to-build-deep-learning-workstation/pcie2.png differ diff --git a/how-to-build-deep-learning-workstation/ws-x299.jpg b/how-to-build-deep-learning-workstation/ws-x299.jpg new file mode 100644 index 0000000..2ee3ccb Binary files /dev/null and b/how-to-build-deep-learning-workstation/ws-x299.jpg differ diff --git a/how-to-use-tensorboard/Demo.gif b/how-to-use-tensorboard/Demo.gif new file mode 100644 index 0000000..36156f7 Binary files /dev/null and b/how-to-use-tensorboard/Demo.gif differ diff --git a/how-to-use-tensorboard/index.html b/how-to-use-tensorboard/index.html new file mode 100644 index 0000000..030197c --- /dev/null +++ b/how-to-use-tensorboard/index.html @@ -0,0 +1,1554 @@ + + + + + + + + + + + + + + + + + + + + + + + 如何使用 TensorBoard - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + + + + +
    +
    + + + + + + + +

    如何使用 TensorBoard

    +

    本文会介绍如何使用 tensorboard 进行可视化。

    +

    tensorboardX

    +

    安装

    +

    在使用之前,可以先看看环境配置--tensorboard

    +

    为了在 PyTorch 里愉快地使用 TensorBoard,目前建议使用 tensorboardX 写出 events.out 文件。

    +

    下面是安装命令:

    +
    pip install tensorboard tensorboardx
    +
    + +

    使用

    +

    万变不离其宗,使用方法首先应该查看文档:https://tensorboardx.readthedocs.io/en/latest/tensorboard.html

    +

    这里我以 PyTorch 训练 CRNN 模型为例,介绍如何可视化以下几个内容:

    +
      +
    • 可视化模型结构
    • +
    • 按 epoch 可视化 loss、acc
    • +
    • 按 batch 可视化 loss、acc
    • +
    • 可视化训练过程中 loss 比较高的样本(badcase)
    • +
    +

    使用 TensorBoard 需要做以下两件事:

    +
      +
    • 在代码中对需要可视化的地方添加写出代码
    • +
    • 打开 TensorBoard 服务
    • +
    +

    创建文件对象(writer)

    +
    import time
    +from tensorboardX import SummaryWriter
    +
    +now = time.strftime("%Y%m%d_%H%M%S", time.localtime())
    +model_name = f'crnn_{now}'
    +print(model_name)
    +writer = SummaryWriter(f'logs/{model_name}')
    +
    + +

    使用上面的代码即可创建一个 writer 对象,之后我们就可以使用这个 writer 写出我们想要写出的东西。

    +

    训练一段时间以后,会在 logs 文件夹下构建以下文件结构:

    +
    logs
    +└── crnn_20190630_200056
    +    ├── epoch
    +    │   ├── acc
    +    │   │   ├── train
    +    │   │   │   └── events.out.tfevents.1561896176.ypw-black
    +    │   │   └── valid
    +    │   │       └── events.out.tfevents.1561896176.ypw-black
    +    │   ├── error_rate
    +    │   │   ├── train
    +    │   │   │   └── events.out.tfevents.1561896176.ypw-black
    +    │   │   └── valid
    +    │   │       └── events.out.tfevents.1561896176.ypw-black
    +    │   └── loss
    +    │       ├── train
    +    │       │   └── events.out.tfevents.1561896176.ypw-black
    +    │       └── valid
    +    │           └── events.out.tfevents.1561896176.ypw-black
    +    └── events.out.tfevents.1561896056.ypw-black
    +
    + +

    打开 TensorBoard 服务

    +

    安装了 TensorBoard 以后,直接使用下面的命令就可以打开 TensorBoard 服务:

    +
    tensorboard --logdir=logs
    +
    + +

    假设你的服务器 IP 地址是 192.168.8.100,只需要在浏览器里输入 http://192.168.8.100:6006 就可以打开 TensorBoard 面板。

    +

    可视化模型结构

    +

    模型结构的可视化非常简单,只需要构建一个输入 tensor 即可:

    +
    model = Model(n_classes, input_shape=(3, height, width))
    +inputs = torch.zeros((1, 3, height, width))
    +writer.add_graph(model, inputs)
    +
    + +

    然后你就可以在 http://192.168.8.100:6006/#graphs 里看到你的模型结构。

    +

    Model

    +

    双击 Model 就可以展开它,下面是展开到合理程度的模型结构图:

    +

    CRNN

    +

    记录标量(scalar)

    +

    使用 writer.add_scalar 就能轻松画出 loss 曲线,下面是经过简化的训练函数:

    +
    def train(model, optimizer, epoch, dataloader, writer):
    +    # ...
    +    for batch_index, (data, target) in enumerate(pbar):
    +        # ...
    +        output = model(data)
    +        loss = criterion(output, target)
    +        acc = calc_acc(target, output)
    +        # ...
    +        iteration = (epoch - 1) * len(dataloader) + batch_index
    +        writer.add_scalar('train/loss', loss, iteration)
    +        writer.add_scalar('train/acc', acc, iteration)
    +        writer.add_scalar('train/error_rate', 1 - acc, iteration)
    +
    + +

    为了让多个图绘制在一个标签下,斜杠前面的名称需要统一,我这里以 train/ 表示,在 TensorBoard 里就可以统一绘制在 train 这个标签内,展开和合并都比较方便。

    +

    训练完以后的曲线如图:

    +

    scalar

    +

    这里有一个小技巧,如果你想可视化正确率这种接近 1 的指标,最好使用错误率(1减正确率),因为当正确率非常接近 1 的时候,很难看出来趋势。使用 TensorBoard 切换到对数尺度下,就能轻松看出错误率的趋势了:

    +

    logscale

    +

    在 30k 的时候,我把学习率降低了 10倍,继续训练了 10代,如果看上面的图,只能看出来 loss 更平缓了,但是下面的对数尺度下就可以明显看出来 loss 从 8e-3 下降到了 2e-3,下降了 4 倍。

    +

    记录多个标量(scalars)

    +

    很多时候我们都需要使用训练集的 loss 和验证集的 loss 做对比,以判断模型有没有过拟合。这时候使用 writer.add_scalars 就可以将多个标量绘制在同一张图里进行对比。下面是示例代码:

    +
    for epoch in range(1, epochs + 1):
    +    train_loss, train_acc = train(model, optimizer, epoch, train_loader, writer)
    +    valid_loss, valid_acc = valid(model, epoch, valid_loader, writer)
    +
    +    writer.add_scalars('epoch/loss', {'train': train_loss, 'valid': valid_loss}, epoch)
    +    writer.add_scalars('epoch/acc', {'train': train_acc, 'valid': valid_acc}, epoch)
    +    writer.add_scalars('epoch/error_rate', {'train': 1 - train_acc, 'valid': 1 - valid_acc}, epoch)
    +
    + +

    scalars

    +

    可以看到在对数尺度下,loss 和错误率还有向下走的趋势,可以继续训练。

    +

    记录图像(images)

    +

    不管是在 GAN 里,还是其他图像任务里,绘制图像都是一个很有用的功能。下面我以绘制 badcase 为例:

    +
    # draw badcase
    +with torch.no_grad():
    +    output_argmax = output.detach().permute(1, 0, 2).argmax(dim=-1)
    +    loss = F.ctc_loss(output_log_softmax, target, input_lengths, target_lengths, reduction='none')
    +    hard_sample = np.argsort(loss.detach().cpu().numpy())[::-1]
    +    data = data.cpu()
    +    target = target.cpu()
    +
    +    nrow = 4
    +    ncol = 4
    +    fig = plt.figure(figsize=(12, 6))
    +    for i, index in enumerate(hard_sample[:nrow*ncol]):
    +        plt.subplot(ncol, nrow, i+1)
    +        plt.axis('off')
    +        plt.imshow(data[index].numpy().transpose(1, 2, 0))
    +        s = f'true: {decode_target(target[index])}\npred: {decode(output_argmax[index])}'
    +        plt.title(s)
    +
    +    fig.canvas.draw()
    +    image = np.array(fig.canvas.renderer.buffer_rgba())
    +    plt.close()
    +    writer.add_image('train/badcase', to_tensor(image), epoch)
    +
    + +

    首先为了避免影响训练,整个代码都需要在 torch.no_grad() 下进行。然后为了获取不好识别的样本,需要重新计算 loss,并且添加 reduction='none' 以计算每个样本的 loss。

    +

    OCR 问题既需要图像,又需要文本,所以这里我们使用 matplotlib 绘制图像,然后得到矩阵比较方便。如果你只想拼接多个图像,可以使用 from torchvision.utils import make_grid 函数。

    +

    下面是训练过程中的 badcase:

    +

    badcase

    +

    可以看到大部分图像都是因为 0 和 O 识别不对,其实前面几个图我也看不出来到底是 0 还是 O。

    +

    完整代码

    +

    以上几个例子的完整代码在 https://github.com/ypwhs/captcha_break 项目中,文件名是 ctc_pytorch_tensorboard.ipynb ,该项目解决了验证码识别的问题,最终训练到了 0.9957 的准确率。

    +

    总结

    +

    使用 TensorBoard 可以监控训练过程中的 loss 趋势,及早发现问题。训练多个模型以后,还可以把多个模型的曲线放在一张图里横向对比。另外 badcase 分析也可以发现更多潜在的问题,为之后的优化寻找方向。可以说 TensorBoard 是每一个深度学习从业者的必备技能。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imgs/image(1).png b/imgs/image(1).png new file mode 100644 index 0000000..43b2404 Binary files /dev/null and b/imgs/image(1).png differ diff --git a/imgs/image(10).png b/imgs/image(10).png new file mode 100644 index 0000000..34904a9 Binary files /dev/null and b/imgs/image(10).png differ diff --git a/imgs/image(13).png b/imgs/image(13).png new file mode 100644 index 0000000..c8232ee Binary files /dev/null and b/imgs/image(13).png differ diff --git a/imgs/image(14).png b/imgs/image(14).png new file mode 100644 index 0000000..1183aa6 Binary files /dev/null and b/imgs/image(14).png differ diff --git a/imgs/image(15).png b/imgs/image(15).png new file mode 100644 index 0000000..4201ad3 Binary files /dev/null and b/imgs/image(15).png differ diff --git a/imgs/image(16).png b/imgs/image(16).png new file mode 100644 index 0000000..cc6b5c9 Binary files /dev/null and b/imgs/image(16).png differ diff --git a/imgs/image(17).png b/imgs/image(17).png new file mode 100644 index 0000000..63c9169 Binary files /dev/null and b/imgs/image(17).png differ diff --git a/imgs/image(21).png b/imgs/image(21).png new file mode 100644 index 0000000..3d889fd Binary files /dev/null and b/imgs/image(21).png differ diff --git a/imgs/image(22).png b/imgs/image(22).png new file mode 100644 index 0000000..fcf061a Binary files /dev/null and b/imgs/image(22).png differ diff --git a/imgs/image(24).png b/imgs/image(24).png new file mode 100644 index 0000000..1e93fce Binary files /dev/null and b/imgs/image(24).png differ diff --git a/imgs/image(25).png b/imgs/image(25).png new file mode 100644 index 0000000..1be22e6 Binary files /dev/null and b/imgs/image(25).png differ diff --git a/imgs/image(26).png b/imgs/image(26).png new file mode 100644 index 0000000..a5401e2 Binary files /dev/null and b/imgs/image(26).png differ diff --git a/imgs/image(27).png b/imgs/image(27).png new file mode 100644 index 0000000..9e6d68d Binary files /dev/null and b/imgs/image(27).png differ diff --git a/imgs/image(28).png b/imgs/image(28).png new file mode 100644 index 0000000..da49747 Binary files /dev/null and b/imgs/image(28).png differ diff --git a/imgs/image(29).png b/imgs/image(29).png new file mode 100644 index 0000000..9a557a1 Binary files /dev/null and b/imgs/image(29).png differ diff --git a/imgs/image(30).png b/imgs/image(30).png new file mode 100644 index 0000000..1b855dd Binary files /dev/null and b/imgs/image(30).png differ diff --git a/imgs/image(31).png b/imgs/image(31).png new file mode 100644 index 0000000..bec4cd1 Binary files /dev/null and b/imgs/image(31).png differ diff --git a/imgs/image(32).png b/imgs/image(32).png new file mode 100644 index 0000000..06d37da Binary files /dev/null and b/imgs/image(32).png differ diff --git a/imgs/image(33).png b/imgs/image(33).png new file mode 100644 index 0000000..e0fcb30 Binary files /dev/null and b/imgs/image(33).png differ diff --git a/imgs/image(4).png b/imgs/image(4).png new file mode 100644 index 0000000..a1144f7 Binary files /dev/null and b/imgs/image(4).png differ diff --git a/imgs/image(40).png b/imgs/image(40).png new file mode 100644 index 0000000..c74060f Binary files /dev/null and b/imgs/image(40).png differ diff --git a/imgs/image(41).png b/imgs/image(41).png new file mode 100644 index 0000000..4974adc Binary files /dev/null and b/imgs/image(41).png differ diff --git a/imgs/image(43).png b/imgs/image(43).png new file mode 100644 index 0000000..91ece36 Binary files /dev/null and b/imgs/image(43).png differ diff --git a/imgs/image(45).png b/imgs/image(45).png new file mode 100644 index 0000000..8cdca8b Binary files /dev/null and b/imgs/image(45).png differ diff --git a/imgs/image(46).png b/imgs/image(46).png new file mode 100644 index 0000000..480785d Binary files /dev/null and b/imgs/image(46).png differ diff --git a/imgs/image(48).png b/imgs/image(48).png new file mode 100644 index 0000000..b334c4b Binary files /dev/null and b/imgs/image(48).png differ diff --git a/imgs/image(49).png b/imgs/image(49).png new file mode 100644 index 0000000..af05777 Binary files /dev/null and b/imgs/image(49).png differ diff --git a/imgs/image(5).png b/imgs/image(5).png new file mode 100644 index 0000000..e0fcb30 Binary files /dev/null and b/imgs/image(5).png differ diff --git a/imgs/image(51).png b/imgs/image(51).png new file mode 100644 index 0000000..30e1202 Binary files /dev/null and b/imgs/image(51).png differ diff --git a/imgs/image(52).png b/imgs/image(52).png new file mode 100644 index 0000000..94c7cfe Binary files /dev/null and b/imgs/image(52).png differ diff --git a/imgs/image(53).png b/imgs/image(53).png new file mode 100644 index 0000000..f976781 Binary files /dev/null and b/imgs/image(53).png differ diff --git a/imgs/image(54).png b/imgs/image(54).png new file mode 100644 index 0000000..444fbb2 Binary files /dev/null and b/imgs/image(54).png differ diff --git a/imgs/image(56).png b/imgs/image(56).png new file mode 100644 index 0000000..8dbb5ea Binary files /dev/null and b/imgs/image(56).png differ diff --git a/imgs/image(58).png b/imgs/image(58).png new file mode 100644 index 0000000..f253cf6 Binary files /dev/null and b/imgs/image(58).png differ diff --git a/imgs/image(6).png b/imgs/image(6).png new file mode 100644 index 0000000..1b7981c Binary files /dev/null and b/imgs/image(6).png differ diff --git a/imgs/image(7).png b/imgs/image(7).png new file mode 100644 index 0000000..08330d2 Binary files /dev/null and b/imgs/image(7).png differ diff --git a/imgs/image(8).png b/imgs/image(8).png new file mode 100644 index 0000000..c14c608 Binary files /dev/null and b/imgs/image(8).png differ diff --git a/imgs/image.png b/imgs/image.png new file mode 100644 index 0000000..676f501 Binary files /dev/null and b/imgs/image.png differ diff --git a/imgs/ping-mu-kuai-zhao-20190613-01.00.31.png b/imgs/ping-mu-kuai-zhao-20190613-01.00.31.png new file mode 100644 index 0000000..e9b8e68 Binary files /dev/null and b/imgs/ping-mu-kuai-zhao-20190613-01.00.31.png differ diff --git a/imgs/ping-mu-kuai-zhao-20190710-00.22.56.png b/imgs/ping-mu-kuai-zhao-20190710-00.22.56.png new file mode 100644 index 0000000..6986f13 Binary files /dev/null and b/imgs/ping-mu-kuai-zhao-20190710-00.22.56.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..4882400 --- /dev/null +++ b/index.html @@ -0,0 +1,1271 @@ + + + + + + + + + + + + + + + + + + + + + + + 首页 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    深度学习工程师生存指南

    +

    + Size Stars

    +

    在线阅读:https://dl.ypw.io
    +在线阅读:https://ypwhs.github.io/dl-engineer-guidebook/
    +项目地址:https://github.com/ypwhs/dl-engineer-guidebook

    +
      +
    • 持续关注请点 Watch
    • +
    • 收藏项目请点 Star
    • +
    • 贡献内容请点 Fork
    • +
    • 提问或建议请点 Issue
    • +
    +

    本书会讲述一个深度学习工程师所需的所有东西:

    +
      +
    • 如何配置一台深度学习工作站?
        +
      • CPU
      • +
      • 主板
      • +
      • 显卡
      • +
      • 硬盘
      • +
      • 内存
      • +
      • 电源
      • +
      • 网卡
      • +
      • 机箱
      • +
      • 显示器
      • +
      • 键盘鼠标
      • +
      +
    • +
    • 本地设备 +
    • +
    • macOS 软件
        +
      • 终端
      • +
      • 编辑器
      • +
      • 浏览器
      • +
      • 开发软件
      • +
      • 实用工具
      • +
      • 虚拟机
      • +
      +
    • +
    • macOS 环境
        +
      • Homebrew
      • +
      • oh my zsh
      • +
      • 必备软件
          +
        • 终端
        • +
        • 编辑器
        • +
        • 浏览器
        • +
        • 开发软件
        • +
        • 实用工具
        • +
        • 日常应用
        • +
        +
      • +
      • 必备命令
      • +
      +
    • +
    • Python 环境
        +
      • Anaconda
      • +
      • Python 库
      • +
      +
    • +
    • Ubuntu 装机步骤
        +
      • 安装 Ubuntu
      • +
      • 配置 ssh
      • +
      • 配置 sudo 免密码 和 apt 源(推荐)
      • +
      • 安装 oh my zsh 以及常用命令(推荐)
      • +
      • 安装 NVIDIA 驱动、CUDA 和 cuDNN(分为 apt 和 run 两种安装方式)
      • +
      • 安装 Anaconda 和 Python 库
      • +
      +
    • +
    • Ubuntu 环境
        +
      • CUDA
      • +
      • cuDNN
      • +
      • TensorFlow
      • +
      • PyTorch
      • +
      • 必备命令
          +
        • curl
        • +
        • tmux 与 iTerm2 结合使用
        • +
        • screen 后台运行命令
        • +
        +
      • +
      +
    • +
    • 常用 Linux 命令
        +
      • 文件查看
      • +
      • 文件读写
      • +
      • 打包压缩
      • +
      • 权限管理
      • +
      • 进程管理
      • +
      • 磁盘管理
      • +
      • 系统管理
      • +
      • 系统监测
      • +
      • 网络通信
      • +
      +
    • +
    • CV 学习资源
        +
      • 公开课
      • +
      • 网站
      • +
      • 书籍
      • +
      +
    • +
    • 常用 CV 数据集
        +
      • 数据集使用方法
      • +
      • MNIST
      • +
      • CIFAR
      • +
      • ImageNet
      • +
      • VOC
      • +
      • COCO
      • +
      • CelebA
      • +
      +
    • +
    • 在 ImageNet 上表现出色的经典模型
        +
      • 预训练模型使用方法
          +
        • TensorFlow
        • +
        • PyTorch
        • +
        +
      • +
      • 模型论文
      • +
      +
    • +
    • 如何使用 TensorBoard
        +
      • 安装
      • +
      • 使用
          +
        • 创建文件对象(writer)
        • +
        • 打开 TensorBoard 服务
        • +
        • 可视化模型结构
        • +
        • 记录标量(scalar)
        • +
        • 记录多个标量(scalars)
        • +
        • 记录图像(images)
        • +
        • 完整代码
        • +
        +
      • +
      • 总结
      • +
      +
    • +
    • 离线 Python 环境
        +
      • 下载 conda 安装包
      • +
      • 下载 pkg 文件和 whl 文件
          +
        • 启动 miniconda 容器
        • +
        • 添加 conda 源(可选)
        • +
        • 下载 pkg 文件
        • +
        • 配置 pip 源(可选)
        • +
        • 下载 whl 文件
        • +
        +
      • +
      • 在离线机器上进行安装
          +
        • 将离线包传到离线机器上
        • +
        • 安装 conda
        • +
        • 创建 Python 虚拟环境
        • +
        • 安装 whl 库
        • +
        +
      • +
      +
    • +
    + + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/tablesort.js b/js/tablesort.js new file mode 100644 index 0000000..69c0ff3 --- /dev/null +++ b/js/tablesort.js @@ -0,0 +1,6 @@ +document$.subscribe(function() { + var tables = document.querySelectorAll("article table:not([class])") + tables.forEach(function(table) { + new Tablesort(table) + }) +}) \ No newline at end of file diff --git a/linux-command/index.html b/linux-command/index.html new file mode 100644 index 0000000..d605efe --- /dev/null +++ b/linux-command/index.html @@ -0,0 +1,3358 @@ + + + + + + + + + + + + + + + + + + + + + + + 常用 Linux 命令 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    常用 Linux 命令

    +

    这里介绍了最常用的 Linux 命令,有一些在工作中是不可或缺的,还有一些能够极大的提高效率。想要熟练地使用多加练习即可!

    +

    man

    +

    Linux 下的帮助命令。

    +

    授人以鱼不如授人以渔,首先应该教会大家查文档,而不是教会大家所有命令的用法。

    +

    如:man ls可以查看 ls 命令的帮助文档。

    +

    提示:按 q 退出帮助页面。

    + + +

    文件查看

    +

    cd

    +

    切换工作目录。

    +

    ~ 是 home directory 的意思,.表示目前所在的目录,..表示目前目录位置的上一层目录。

    +

    cd .. 返回上一层目录。

    +

    ls

    +

    ls 是 list 的缩写,用来显示目标列表。

    +

    llls -lh 的别名,列出的信息更加详细。

    +

    pwd

    +

    pwd 命令以绝对路径的方式显示用户当前工作目录。

    +

    cat

    +

    显示文件的内容:cat file

    +

    当文件较大时,文本会在屏幕上快速滚动,可以使用Ctrl+S停止滚动,Ctrl+Q恢复滚动,Ctrl+C退出当前命令。

    + +

    显示文件开头的内容,比如:head -n 5 train.csv 可以显示训练集 csv 前五行内容。

    +

    tail

    +

    显示文件尾部的内容。tailhead 默认显示 10 行。

    +

    find

    +

    在指定目录下查找文件。

    +

    grep

    +

    筛选命令,比如我想查找许多文件里面的 markdown 文件:

    +
    ls -lh | grep .md
    +
    + +
    ➜  pytorch git:(ff608a9) ✗ ls -lh | grep .md
    +-rw-rw-r--  1 ypw ypw  15K 12月  5  2018 CONTRIBUTING.md
    +-rw-rw-r--  1 ypw ypw  285 12月  4  2018 mypy-README.md
    +-rw-rw-r--  1 ypw ypw  14K 12月  5  2018 README.md
    +
    + +

    whereis

    +

    可以查找包含指定关键字的文件,如 whereis python 可以查找所有的文件名包含 python 的文件路径:

    +
    ➜  ~ whereis python
    +python: /usr/bin/python2.7 /usr/bin/python3.5 /usr/bin/python /usr/bin/python3.5m /usr/lib/python2.7 /usr/lib/python3.5 /etc/python2.7 /etc/python3.5 /etc/python /usr/local/lib/python2.7 /usr/local/lib/python3.5 /usr/include/python3.5m /usr/share/python /home/ypw/anaconda3/bin/python3.6 /home/ypw/anaconda3/bin/python3.6m-config /home/ypw/anaconda3/bin/python3.6-config /home/ypw/anaconda3/bin/python3.6m /home/ypw/anaconda3/bin/python /usr/share/man/man1/python.1.gz
    +
    + +

    which

    +

    可以查找当前使用的命令的绝对路径。

    +

    which python 可以显示 /home/ypw/anaconda3/bin/python

    +

    但是当你激活一个新的环境以后,就会得到不一样的结果:

    +
    ➜  ~ source activate tensorflow
    +(tensorflow) ➜  ~ which python
    +/home/ypw/anaconda3/envs/tensorflow/bin/python
    +
    + +

    locate

    +

    locate 命令会寻找包含关键字的所有文件路径。

    +

    文件读写

    +

    mkdir

    +

    创建文件夹。

    +

    touch

    +

    创建空文件。

    +

    rm

    +

    移除文件。移除文件夹时需要使用rm -r,没有权限时需要rm -rf

    +

    此命令比较危险,注意不要写成这样:rm -rf / tmp,这样会删除/下的所有文件,属于删库跑路行为。

    +

    cp

    +

    复制文件:cp src dst

    +

    复制文件夹:cp -r src dst

    +

    mv

    +

    移动命令。

    +

    例如:mv source destination

    + + +

    vim

    +

    编辑文件的命令,学习曲线比较陡峭,建议搜索相关教程学习。

    +

    nano

    +

    Ubuntu 自带的编辑文件的命令。

    +

    使用方法:

    +
    nano ~/.ssh/authorized_keys
    +
    + +

    提示:Ctrl+O 可以保存文件,Ctrl+K 可以删除整行,Ctrl+W 可以查找文本,Ctrl+X 可以退出编辑器,其他特性可以根据底部的快捷键自行学习。

    +

    打包压缩

    +

    zip

    +

    压缩命令,通过zip file.zip file可以压缩一个文件,通过zip files.zip -r dir可以压缩整个文件夹。

    +

    unzip

    +

    解压由zip 命令压缩的 .zip 文件。

    +

    例如:unzip files.zip

    +

    tar

    +

    *.tar 打包文件:只是把很多小文件拼接在一起,速度快,不占用 CPU,比如 ImageNet 数据集就是一个打包文件,解包的速度非常快。打包后的文件大小和原始文件夹的大小基本一致。

    +

    *.tar.gz 压缩文件:先打包成一个文件,然后再压缩一遍,就是这个格式。如果文件是未压缩的格式,比如文本文件,使用这个格式可以有很高的压缩比。注意:jpg 和 png 格式是压缩后的格式,只打包就行,如果对 ImageNet 数据集先打包再压缩,就会有很长的耗时,并且文件不会明显变小。

    +
      +
    • c:打包
    • +
    • x:解包
    • +
    • v:输出详细信息
    • +
    • f:指定打包文件
    • +
    • z:使用 gzip 压缩格式
    • +
    +

    打包文件夹:tar -cvf files.tar dir

    +

    解包:tar -xvf files.tar

    +

    压缩文件夹:tar -czvf files.tar.gz dir

    +

    解压:tar -xzvf files.tar.gz

    +

    权限管理

    +

    sudo

    +

    以 root 权限执行命令,比如 sudo reboot 可以重启机器,普通权限无法重启。

    +

    su

    +

    切换用户,比如 sudo su ypw 可以将当前用户切换到 ypw 用户。

    +

    chmod

    +

    修改权限的命令,比如:sudo chmod -R 777 data 可以把 data 文件夹修改为任何人可以读写。

    +

    chown

    +

    修改所有者的命令,比如:sudo chown -R ypw data 可以把 data 文件夹的所有权改为 ypw。

    +

    passwd

    +

    修改密码命令,直接执行 passwd 可以修改当前用户密码。

    +

    强制修改某个用户的密码:sudo passwd ypw

    +

    进程管理

    +

    ps

    +

    ps aux 可以列出所有进程的详细信息。

    +

    配合 grep 命令用比较好,比如 ps aux | grep ipython | grep -v grep

    +

    首先使用 ps aux 获取所有的进程信息,然后用 grep ipython 查找带有 python 的进程,最后使用 grep -v grep 过滤 grep 进程本身。

    +

    kill

    +

    杀掉执行中的进程,刚才 ps 命令可以得到进程号,你可以根据进程号删除该进程,如 kill 8339

    + + +

    killall

    +

    通过进程名来杀掉进程,请确保你不会影响其他人的情况下使用该命令。

    +

    如果同事正在使用 python 跑程序,你也在使用 python 跑程序,在你执行完 killall python 以后,你们的 python 进程都会被杀掉。

    +

    磁盘管理

    +

    df

    +

    查看磁盘空间,比如 df -h 可以显示下面的内容:

    +
    Filesystem      Size  Used Avail Use% Mounted on
    +udev             32G     0   32G   0% /dev
    +tmpfs           6.3G  9.5M  6.3G   1% /run
    +/dev/nvme0n1p2  916G  248G  622G  29% /
    +tmpfs            32G  679M   31G   3% /dev/shm
    +tmpfs           5.0M  4.0K  5.0M   1% /run/lock
    +tmpfs            32G     0   32G   0% /sys/fs/cgroup
    +/dev/nvme0n1p1  511M  3.5M  508M   1% /boot/efi
    +tmpfs           6.3G   32K  6.3G   1% /run/user/1000
    +
    + +

    使用 df -ih 可以查看 Inodes 使用情况,如果你的磁盘下存在很多小文件,那么你可以使用这个命令查看文件表是否用完了。

    +

    du

    +

    可以查看文件夹大小,比如:du -h ImageNet 可以输出下面的内容:

    +
    ......
    +163M    ImageNet/train/n12620546
    +128M    ImageNet/train/n02108551
    +127M    ImageNet/train/n15075141
    +140G    ImageNet/train
    +6.4G    ImageNet/val
    +146G    ImageNet
    +
    + +

    mount

    +

    挂载磁盘的命令,挂载硬盘:

    +
    sudo mount -t ext4 /dev/nvme0n1p1 /data
    +
    + +

    挂载 samba 网络盘:

    +
    sudo mount -t cifs -o username=ypw,password=**** //192.168.8.57/dataset /home/ypw/dataset
    +
    + +

    注意:此处需要 sudo apt install cifs-utils

    +

    系统管理

    +

    apt

    +

    Ubuntu 系统的包管理器,用于安装和卸载软件包。

    +

    安装:sudo apt install curl

    +

    卸载:sudo apt purge curl

    +

    export

    +

    设置环境变量命令,一般写在 .bashrc.zshrc 文件中,例如:

    +
    export PATH=/usr/local/cuda/bin:$PATH
    +
    + +

    的功能是把 /usr/local/cuda/bin 目录添加到 PATH 的最前面,这样就可以直接在命令行使用 /usr/local/cuda/bin 目录下的 nvcc 命令。

    +

    source

    +

    更新环境变量。

    +

    如 zsh 用户更新了 ~/.zshrc 以后,可以使用下面的命令更新环境变量:

    +
    source ~/.zshrc
    +
    + +

    update-alternatives

    +

    切换命令版本。比如你装了很多个 CUDA 版本:

    +
    sudo update-alternatives --config cuda
    +
    +There are 3 choices for the alternative cuda (providing /usr/local/cuda).
    +
    +  Selection    Path                  Priority   Status
    +------------------------------------------------------------
    +  0            /usr/local/cuda-12.1   121       auto mode
    +  1            /usr/local/cuda-11.3   113       manual mode
    +* 2            /usr/local/cuda-11.7   117       manual mode
    +  3            /usr/local/cuda-12.1   121       manual mode
    +
    +Press <enter> to keep the current choice[*], or type selection number:
    +
    + +

    你就可以使用 sudo update-alternatives --config cuda 命令选择你想用的版本,输入数字,然后回车,就可以切换过去。

    +

    echo

    +

    可以输出环境变量。

    +

    例如:echo $PATH

    +

    service

    +

    开启关闭服务的命令,如:

    +
    sudo service network-manager restart
    +
    + +

    shutdown

    +

    关机命令。

    +

    例如:sudo shutdown -t 0

    +

    reboot

    +

    重启命令。

    +

    例如:sudo reboot

    +

    系统监测

    +

    uname

    +

    显示当前的系统信息。

    +

    uname -a 显示全部的信息,如内核版本号、硬件架构、主机名称和操作系统类型等。

    +

    top

    +

    实时查看系统的运行状态,如 CPU、内存、进程的信息。

    +

    ifconfig

    +

    这个命令可以查看当前网卡的 ip 地址。如:

    +
    ➜  ~ ifconfig | grep inet
    +          inet addr:192.168.8.100  Bcast:192.168.8.255  Mask:255.255.255.0
    +          inet6 addr: fe80::211d:78f6:888a:1/64 Scope:Link
    +          inet addr:127.0.0.1  Mask:255.0.0.0
    +
    + +

    free

    +

    查看内存使用情况,如:free -h

    +
                  total        used        free      shared  buff/cache   available
    +Mem:            62G        404M         61G        9.4M        891M         61G
    +Swap:          976M          0B        976M
    +
    + +

    网络通信

    +

    ping

    +

    测试主机之间网络的连通性。

    +

    例如:ping baidu.com

    +

    ssh

    +

    连接远程服务器:ssh user@192.168.1.100

    +

    映射远程端口:ssh -L 本地端口:远程服务器:远程端口 远程服务器

    +

    例如:ssh -L 8888:localhost:8888 192.168.1.100 可以把服务器上的 jupyter 监听的 8888 端口映射到本地的 8888 端口,然后只需要在浏览器里输入http://localhost:8888 就可以连接远程服务器的 jupyter 了。

    +

    scp

    +

    复制文件/文件夹到远程服务器,或者反向复制,例如:

    +
      +
    • 从本地复制到远程:scp 本地文件 用户名@目标主机:目标主机路径
    • +
    • 从远程复制到本地:scp 用户名@目标主机:目标主机文件 本地地址
    • +
    +

    复制文件:scp filename user@192.168.1.100:/data

    +

    复制文件夹需要添加 -r 参数:scp -r directory user@192.168.1.100:/data

    +

    当你复制大量小文件时,请使用rsync 命令。

    +

    rsync

    +

    同步文件/文件夹命令,带有增量备份功能,速度很快。

    +

    参数:

    +
      +
    • -a,--archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于-rlptgoD。
    • +
    • -v,--verbose 详细模式输出。
    • +
    • -z,--compress 在传输时压缩数据,如果你传输的文件没有压缩过,并且带宽不够大,就可以开启压缩。如果你传输的是图像文件,那么压缩会拖慢传输速度。
    • +
    • --delete,在同步的时候删除多余的文件,这可以确保两个文件夹的一致性。
    • +
    • --exclude,排除文件,可以使用通配符
    • +
    • -P,等同于 --partial --progress,显示备份过程。
    • +
    +

    命令:rsync -avP 源路径 目的地路径,其中源路径可以是本地文件夹路径,也可以是远程路径,目的地路径也可以是本地和远程路径。

    +

    如:

    +
      +
    • 将本地的文件夹同步到服务器:rsync -avP 本地路径 用户名@远程服务器:远程路径
    • +
    • 将服务器上的文件夹同步到本地:rsync -avP 用户名@远程服务器:远程路径 本地路径
    • +
    • 本地拷贝文件夹:rsync -avP 本地源路径 本地目的地路径
    • +
    +

    注意:

    +

    如果同步的源路径后面加了斜杠 /,则同步的目的地不会创建子文件夹。比如将一台服务器上的 home 目录同步另一台服务器:

    +
    rsync -avP 配好的服务器:/home/ypw/ .
    +
    + +

    下面是一个把远程服务器同步到本地的例子:

    + + +

    wget

    +

    从指定的URL下载文件。

    +

    下载单个文件:wget url

    +

    下载并修改文件名:wget -O filename.zip url

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mac-compare/imac-gallery1-201706_GEO_CN.jpg b/mac-compare/imac-gallery1-201706_GEO_CN.jpg new file mode 100644 index 0000000..87437d0 Binary files /dev/null and b/mac-compare/imac-gallery1-201706_GEO_CN.jpg differ diff --git a/mac-compare/imacpro-27-retina-selection-hero.jpg b/mac-compare/imacpro-27-retina-selection-hero.jpg new file mode 100644 index 0000000..478fcfe Binary files /dev/null and b/mac-compare/imacpro-27-retina-selection-hero.jpg differ diff --git a/mac-compare/index.html b/mac-compare/index.html new file mode 100644 index 0000000..668b1af --- /dev/null +++ b/mac-compare/index.html @@ -0,0 +1,1525 @@ + + + + + + + + + + + + + + + + + + + + + + + Mac 对比 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    Mac 对比

    +

    这部分主要介绍苹果公司的电脑产品,以及我正在使用的设备。

    +

    下面的表格是介绍每个产品不同配置的情况(截止至 2019年11月13日):

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    型号CPU(GHz)内存(GB)存储容量(GB)屏幕(寸)重量(千克)价格(元)
    MacBook1.2(3.0)*28256120.92买不到了
    MacBook Air1.6(3.6)*28128131.258899
    MacBook Pro 131.4(3.9)*48128131.379999
    MacBook Pro 132.4(4.1)*48256131.3713899
    MacBook Pro 162.6(4.5)*616512162.018999
    MacBook Pro 162.3(4.8)*8161024162.022199
    Mac mini3.6*481281.36331
    Mac mini3.0(4.1)*682561.38669
    iMac 273.0(4.1)*681024(融合)279.4213832
    iMac 27 (定制)3.6(5.0)*88512279.4221398
    iMac Pro3.2(4.2)*8321024279.738138
    Mac Pro (未发售)3.5(4)*83225618约4万(5999$)
    +

    注:

    +
      +
    • CPU 括号里的数字为 Turbo Boost 以后的频率,后面乘的数字代表核数
    • +
    • iMac 不定制只能买到非固态硬盘
    • +
    • Mac Pro 暂未发售
    • +
    +

    详细信息请查看官网:

    + +

    下面让我们详细介绍这几个型号,以及我的体验和想法。

    +

    MacBook

    +

    MacBook

    +

    从上面的表格可以看到,MacBook 的 CPU 频率是很低的,这是因为没有风扇,所以 CPU 功率非常低。这款笔记本的主要优势在于便携,重量只有 0.92千克,是苹果最轻的笔记本。它非常适合出差的时候带上。用苹果的话说就是“身薄力不薄”,用俗话说就是麻雀虽小五脏俱全。

    +

    写代码的体验上来说,使用起来除了屏幕小,没有缺点,因为代码都是远程执行的,所以它只负责显示代码,进行代码提示,把修改过代码推到服务器上即可。我甚至用它跑过 Windows 虚拟机,除了慢一点,没有任何其他问题。

    +

    需要注意的是,它只有一个 USB-C 口。

    +

    此款是我的旅行必备。

    +

    2019年注:此款已经不卖了,可以购买 MacBook Air。

    +

    MacBook Air

    +

    MacBookAir

    +

    MacBook Air 的价格比 MacBook 便宜一点,性能比 MacBook 好一点,但是重量重一点,多一个 USB-C 口,然后就没有其他的优势了。即使是 MacBook Pro 的双核入门款,重量与 MacBook Air 差不多,CPU 却好了不少,所以我没有买过这一款。

    +

    MacBook Pro

    +

    MacBookPro

    +

    如果是学生党,主推 MacBook Pro。

    +

    从表格中可以看到,从一万到两万都有的选,性能也从 2 核到 8 核,差了几倍。一般来说还是选能买得起的最贵的型号比较好,一步到位免除后患。

    +

    当你使用 PyCharm 写代码的时候,代码提示、Debug 下断点以及 Debug 变量内容的显示都会比较耗费CPU,尽可能买一个速度快的电脑能够节省生命。

    +

    正常操作系统开机以后都会占用 6GB 左右的内存,PyCharm 默认消耗 750MB内存,不过我使用的时候通常会内存不足,所以我会调到 2GB,这样就会用光 8GB 内存,因此选择 16GB 内存是比较充裕的。

    +

    个人觉得如果不放数据集,硬盘选 256GB 是够用的。如果你作为主力机使用,除了写代码还需要放电视剧、照片、手机备份等文件,那么最好按照自己的使用习惯去选择合适的容量。

    +

    我重度使用过 13寸和 15寸的型号。

    +

    Mac mini

    +

    Macmini

    +

    此款上班族可以考虑,它的价格便宜,性价比却很高,八千的价格可以比得上一万八的 MacBook Pro 的性能,不过我没有买过,所以不做过多的评论了。

    +

    iMac

    +

    iMac

    +

    这是我最喜欢的 Mac,因为它的屏幕特别大,分辨率也高(5K),非常适合写代码。我买的是定制的 1TB固态硬盘,另外升级 CPU 为 i7。现在买的话,能够升级到 i9,性能比我正在使用的这台好得多,十分推荐。

    +

    内存条可以在网上购买,自行安装,非常方便,这里不建议升级。

    +

    硬盘强烈建议选固态硬盘,极大提升各大 APP 的启动速度以及响应速度。

    +

    鼠标不推荐,建议选触控板,熟练使用触控板可以高效进行各种操作,比如拖拽、多选、切换应用和屏幕等。

    +

    iMac Pro

    +

    iMacPro

    +

    性能更好了,但是价格也翻倍了,性价比不高。对于深度学习来说没有更大的优势,不过如果不计成本又喜欢黑色的话可以选择这款。

    +

    Mac Pro

    +

    MacPro

    +

    性能很强大,但是现在买不到,单看低配版的性能比不过 iMac 定制版。

    +

    如果选配更高级别的配置,比如加个 Radeon Pro Vega II Duo,据说有 14TFLOPS 的性能,或许可以直接跑深度学习,但是是 A 卡,可能需要踩坑。等到 CoreML 能训练模型的时候,或许可以买一个试试看。

    +

    总结

    +

    学生党按预算选择买得起的最好的 MacBook Pro,有固定工位的学生或上班族可以考虑买 iMac 或者 Mac mini,追求轻便可以选 MacBook。

    +

    最佳搭配是家里放一台 iMac,出门使用 MacBook,使用 iCloud 进行设备之间的文件同步。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mac-compare/mac-mini-hero-201810.jpg b/mac-compare/mac-mini-hero-201810.jpg new file mode 100644 index 0000000..a114fae Binary files /dev/null and b/mac-compare/mac-mini-hero-201810.jpg differ diff --git a/mac-compare/mac-pro.jpg b/mac-compare/mac-pro.jpg new file mode 100644 index 0000000..dc75c14 Binary files /dev/null and b/mac-compare/mac-pro.jpg differ diff --git a/mac-compare/macbook-air-201810-gallery4.jpg b/mac-compare/macbook-air-201810-gallery4.jpg new file mode 100644 index 0000000..4c30223 Binary files /dev/null and b/mac-compare/macbook-air-201810-gallery4.jpg differ diff --git a/mac-compare/macbook-air-space-gray-select-201810.jpg b/mac-compare/macbook-air-space-gray-select-201810.jpg new file mode 100644 index 0000000..f14b950 Binary files /dev/null and b/mac-compare/macbook-air-space-gray-select-201810.jpg differ diff --git a/mac-compare/macbook.png b/mac-compare/macbook.png new file mode 100644 index 0000000..8d963ac Binary files /dev/null and b/mac-compare/macbook.png differ diff --git a/mac-compare/mbp16touch-space-select-201911_GEO_CN.jpg b/mac-compare/mbp16touch-space-select-201911_GEO_CN.jpg new file mode 100644 index 0000000..69b306d Binary files /dev/null and b/mac-compare/mbp16touch-space-select-201911_GEO_CN.jpg differ diff --git a/macos-environment/index.html b/macos-environment/index.html new file mode 100644 index 0000000..947fe1f --- /dev/null +++ b/macos-environment/index.html @@ -0,0 +1,1765 @@ + + + + + + + + + + + + + + + + + + + + + + + macOS 环境 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    macOS 环境

    +

    这篇文章会介绍我在 macOS 的终端里安装的命令和软件。

    +

    脚本式装机:

    +
    # 添加代理
    +export https_proxy=your_proxy_address
    +
    +# 安装 brew,需要手动输入密码,按回车
    +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
    +
    +# 添加环境变量
    +echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/ypw/.zprofile
    +eval "$(/opt/homebrew/bin/brew shellenv)"
    +
    +# 安装常用命令
    +brew install aria2 cmake curl pv htop nano nload nmap p7zip tree wget watch
    +
    +# 安装 Oh-my-zsh
    +sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
    +
    +# 安装 iTerm2
    +brew install --cask iterm2
    +
    +# 安装一些必备软件
    +brew install --cask 1password baidunetdisk caffeine clash-for-windows dingtalk github google-chrome iina hex-fiend istat-menus karabiner-elements netron postman pycharm qbittorrent qq sublime-text macdown tinypng4mac typora visual-studio-code wechat wechatwork xquartz
    +
    +# Clash 解决已损坏问题
    +sudo xattr -r -d com.apple.quarantine /Applications/Clash\ for\ Windows.app
    +
    +# 安装Chrome
    +open https://www.google.cn/chrome/
    +
    +# 安装搜狗输入法
    +open https://pinyin.sogou.com/mac/
    +
    +# 安装 Python x86 (可选)
    +sudo softwareupdate --install-rosetta --agree-to-license
    +
    +wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-x86_64.sh
    +bash Miniconda3-latest-MacOSX-x86_64.sh -b
    +
    +# 安装 Python arm64
    +wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-arm64.sh
    +bash Miniconda3-latest-MacOSX-arm64.sh -b
    +
    +# 安装 Python 环境
    +
    +pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
    +pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm tensorboardx torch torchvision xlrd openpyxl openmim
    +mim install mmdet
    +
    + +

    Homebrew

    +

    安装 Homebrew 之前,建议先通过 App Store 安装 Xcode 并接受 「Xcode and Apple SDKs Agreement」,不然就需要在安装过程中接受协议。

    +

    Homebrew 是 macOS 上的一个包管理器,你可以使用 Homebrew 安装 Apple 没有预装但你需要的东西

    +

    安装 Homebrew 只需要一行命令:

    +
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
    +
    + +

    在终端中运行以下两个命令,将 Homebrew 添加到你的环境变量 PATH 中:

    +
    (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/lhy/.zprofile
    +eval "$(/opt/homebrew/bin/brew shellenv)"
    +
    + +

    这里的 lhy 是用户文件夹,所以不要直接复制这里的命令,Homebrew 安装完成后会提示你需要使用的命令。

    +

    通过 brew --version 测试 Homebrew 是否安装成功:

    +
    brew --version
    +
    + +

    使用 Homebrew 安装一个 wget 吧:

    +
    brew install wget
    +
    + +

    当你需要更新的时候,可以使用下面的命令完成:

    +
    brew update && brew upgrade && brew cleanup
    +
    + +

    这是一条终端命令,用于更新和升级 Homebrew,同时清理过期的包和缓存。具体解释如下:

    +

    brew update:更新 Homebrew 的本地包信息,使其与远程仓库同步。

    +

    brew upgrade:升级已安装的包至最新版本。

    +

    brew cleanup:清理已安装的包中过期的版本和无用的缓存,释放磁盘空间。

    +

    这三个命令可以一起使用,以保持 Homebrew 的最新状态并清理不必要的文件。

    +

    切换源

    +

    如果你觉得使用 brew 安装和更新软件的时候非常慢,可以使用其他的镜像,如清华大学

    +

    使用下面的命令可以加速 brew update

    +
    git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
    +git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git
    +git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git
    +brew update
    +
    + +

    设置下面的环境变量可以加速 brew install

    +
    export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles
    +
    + +

    ZshOh My Zsh

    +

    终端软件安装以后,我们还需要安装一个好用的 shell 解释器,zsh 和 oh my zsh。

    +

    它比默认的 bash 有以下几个优点:

    +
      +
    • 当你使用 tab 提示的时候,如果有多个匹配项,你可以用 tab 进行切换
    • +
    • 当你想使用一个之前输入过的命令的时候,只需要输入首字母,然后按上方向键切换
    • +
    +

    在 macOS 下安装 oh my zsh

    +

    在 macOS 下,首先需要安装 zsh,然后再安装 oh my zsh。

    +

    安装步骤如下:

    + +

    完整命令如下:

    +
    # 安装 zsh
    +brew install zsh zsh-completions
    +# 安装 oh my zsh
    +sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
    +
    + +

    最后需要输入一次密码,记得输入正确,否则下一次启动终端就不会使用 zsh。如果你不小心错过了,可以用下面的命令手动切换默认终端:

    +
    chsh -s /bin/zsh
    +
    + +

    检查 zsh 是否安装成功:

    +
    echo $SHELL
    +
    + +

    如果输出结果为 /bin/zsh,则表示你正在使用 zsh。

    +

    必备软件

    +

    使用 homebrew-cask 可以轻松安装各种 macOS 软件,下面的命令可以安装一些必备软件:

    +

    终端

    +
    brew install --cask iTerm2
    +
    + +

    编辑器

    +
    brew install --cask Sublime-Text MacDown Typora Hex-Fiend 
    +
    + +

    浏览器

    +
    brew install --cask Google-Chrome
    +
    + +

    开发软件

    +
    brew install --cask PyCharm miniconda GitHub Postman
    +
    + +

    实用工具

    +
    brew install --cask Netron Karabiner-Elements The-Unarchiver Caffeine
    +
    + +

    日常应用

    +
    brew install --cask WeChat QQ IINA BaiduNetdisk
    +
    + +

    必备命令

    +
    brew install git htop nload wget
    +
    + +

    git

    +

    git 是代码管理工具。

    +

    htop

    +

    htop 是一个系统监控与进程管理软件, 如:

    + + +

    nload

    +

    nload 是一个网速监控命令,你可以用它查看比如打包 docker 的时候的网速如何,是否在下载依赖的软件包。

    +

    下面是运行 https://www.speedtest.net 的时候监控 nload 的过程:

    + + +

    wget

    +

    很方便的命令行下载工具,比如:

    +
    wget https://repo.anaconda.com/archive/Anaconda3-2019.03-MacOSX-x86_64.sh
    +bash Anaconda3-2019.03-MacOSX-x86_64.sh
    +
    + +

    通过上面的命令,你可以下载 Anaconda 安装包,然后安装 Anaconda。

    +

    通过 -c 参数,可以接着上次的进度继续下载。

    +

    如:

    + + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/macos-software/index.html b/macos-software/index.html new file mode 100644 index 0000000..7a0e001 --- /dev/null +++ b/macos-software/index.html @@ -0,0 +1,2098 @@ + + + + + + + + + + + + + + + + + + + + + + + macOS 软件 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    macOS 软件

    +

    下面是我安装的与工作有关的软件。

    +

    本篇文章会介绍这些软件的作用,大部分软件可以通过命令直接安装,参考 macOS 环境-必备软件

    +

    终端

    +

    iTerm2

    +

    终端首选 iTerm,最大的好处是可以结合 tmux 分屏使用,比如:

    +

    iTerm2

    +

    快捷键配置

    +

    开启 ⌘←, ⌘→ 和 ⌥←, ⌥→ 快捷键,可以直接跳到行首,以及跳过单词,在输入很长的命令的时候很有用。

    +

    首先打开 iTerm2 的偏好设置(Preferences),然后切换到 Profiles,在右边找到 Keys 快捷键配置:

    +

    iTerm2->Prefences->Profiles->Keys

    +

    点击 Key Mappings 下面的加号(+),按下面的表格添加快捷键:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Keyboard ShortcutActionEsc+
    ⌘←Send Escape SequenceOH
    ⌘→Send Escape SequenceOF
    ⌥←Send Escape Sequencebb
    ⌥→Send Escape Sequenceff
    +

    如图:

    +

    +

    如果弹出 Warning,直接点确定即可。如果点了确定没反应,不用管它,继续把配置加完,然后重新开启软件就行。

    +

    关闭默认非活跃窗口变灰的选项

    +

    取消勾选Preferences -> Appearance -> Dim inactive split panes即可。

    +

    编辑器

    +

    Sublime Text

    +

    Sublime Text 是一个非常轻量化的文本编辑器,启动迅速,支持各种语言的代码高亮。

    +

    当你只想打开庞大工程里的一个文件的时候,你就可以用它来阅读和修改代码。

    +

    SublimeText3

    +

    MacDown

    +

    MacDown

    +

    MacDown 是一个 markdown 编辑器,支持 Markdown 以及 LaTeX,写文章必备。

    +

    Typora

    +

    另一个 Markdown 编辑器,与 MacDown 不同在于,MacDown 是分栏编辑,左边 Markdown,右边实时渲染,而 Typora 只有一个编辑界面,实时写实时渲染。

    +

    Typora

    +

    Hex Fiend

    +

    HexFiend

    +

    Hex Fiend 是一个十六进制编辑器,当你想查看一个二进制文件的内容的时候就可以使用它,比如我会用它来检查我写出的模型权值文件。因为它可以秒开任何大小的文件,有时候我也会用它来查看几百兆的文本文件。

    +

    浏览器

    +
      +
    • Chrome
    • +
    • Chrome 插件
    • +
    +

    Chrome

    +

    {% embed url="https://www.google.com/chrome/" %}

    +

    目前 Chrome 应该是最受欢迎的浏览器:

    +

    图片来自维基百科

    +

    这里建议使用 Chrome 作为主力浏览器,原因如下:

    +
      +
    • 简洁
    • +
    • 插件强大且免费(Safari 的某些插件是收费的)
    • +
    +

    常用插件

    +

    Adblock Plus

    +

    拦截广告的好工具。

    +

    Tampermonkey

    +

    脚本管理器,你可以找到支持各种功能的脚本,比如:

    +
      +
    • 去广告
    • +
    • 下载视频
    • +
    • 你可以自己写 js 脚本以实现一切功能
    • +
    +

    Proxy SwitchyOmega

    +

    可以很方便地切换代理服务器。

    +

    Octotree

    +

    可以在 GitHub 页面展示代码文件结构,非常方便,如图:

    +

    Octotree

    +

    开发软件

    +

    Xcode

    +

    Xcode 是 macOS 上的 IDE,可以开发 macOS、iPhone、iPad、AppleWatch 等平台上的应用,如果你希望在 iPhone 进行调试,你还需要购买 99$ 的开发者证书。我们一般从 AppStore 上下载 Xcode。

    +

    PyCharm

    +

    PyCharm 是我经常使用的 Python IDE,它支持代码高亮、代码提示、调试断点等功能,专业版还支持远程调试,非常适合深度学习从业人员使用。

    +

    因为大多数深度学习工程师都不是直接在训练机器上写代码,而是使用一个终端机器远程 ssh 进行代码调试。那么如果每次都是上传代码、运行 Python 脚本、看报错,那么就会非常低效,因为有可能你载入了五分钟的数据集以后,报错模型的某个层写错了,然后检查半天,上传一个新的代码,然后陷入上面的循环。

    +

    高效一点的方法就是使用 jupyter notebook 进行开发,即使代码报错了也不会直接退出,我们可以在 jupyter notebook 里继续写代码,直到写出正确的代码。那么这仍然不是高效的方法,因为如果我们有一个错误发生在模型内部的 forward 部分,那么我们就需要用 print 大法在出错代码的前后输出矩阵尺寸、数据类型等关键数据,然后根据报错来修 bug。

    +

    那么当我们出现这种报错的时候,使用 PyCharm 的远程调试功能就非常方便了,我们可以在出错的代码前面下断点,然后我们可以看到每个矩阵的尺寸,模型的每一层的参数,不需要写许多 print 去实现我们的想法。如果代码报错是一个除0错误,你还可以直接在变量监视器里面增加一个 x.mean() 的条目,然后实时查看 x 的均值,不需要重新运行代码。

    +

    GitHub Desktop

    +

    GitHub Desktop 是 GitHub 官方客户端,新手必备。

    +

    Postman

    +

    一款非常好用的 API 测试工具,它可以模拟发送 GET、POST 等请求,支持 JSON 语法高亮。

    +

    Postman

    +

    实用工具

    +
      +
    • Netron
    • +
    • Karabiner-Elements
    • +
    • The Unarchiver
    • +
    • iStat Menus
    • +
    • Caffeine
    • +
    • DaisyDisk
    • +
    +

    Netron

    +

    它是一个可视化模型结构的软件,支持的模型文件格式有:ONNX (.onnx, .pb, .pbtxt), Keras (.h5, .keras), Core ML (.mlmodel), Caffe2(predict_net.pb, predict_net.pbtxt), MXNet (.model, -symbol.json) and TensorFlow Lite (.tflite). Netron has experimental support for Caffe (.caffemodel, .prototxt), PyTorch (.pth), Torch (.t7), CNTK (.model, .cntk), PaddlePaddle (__model__), Darknet (.cfg), scikit-learn (.pkl), TensorFlow.js (model.json, .pb) and TensorFlow(.pb, .meta, .pbtxt).

    +

    Netron

    +

    Karabiner-Elements

    +

    Karabiner-Elements 是一个改键工具,机械键盘必备软件。

    +
    +

    适用于macOS的功能强大且稳定的键盘定制器。

    +
    +

    Karabiner-Elements

    +

    我把我的机械键盘的 Command 键和 Option 键替换了,这样就可以像使用原生键盘一样使用我的机械键盘。你还可以把键盘上的 Windows 键和 Alt 键交换位置。

    +

    The Unarchiver

    +

    这是一个解压缩软件,可以直接在 App Store 上下载,免费,支持 zip、rar、tar 等格式。

    +
    +

    The Unarchiver 是一款简单易用的小程序,可以解压许多不同类型的存档文件。 它能够打开 Zip、RAR(包括 v5)、7-zip、Tar、Gzip 和 Bzip2 等常见格式。 它还能打开许多旧格式,例如 StuffIt、DiskDoubler、LZH、ARJ 和 ARC。 它还能打开其他各种文件,例如 ISO 和 BIN 磁盘镜像、部分 Windows .EXE 安装程序。 该列表实际上很长 - 有关完整列表,请查看程序主页。

    +
    +

    Caffeine

    +

    它可以防止你的电脑进入睡眠,你只需要在状态栏点一下就可以打开和关闭,比在设置里面操作方便不少。

    +

    iStat Menus

    +

    这个软件可以监控 Mac 的 CPU、内存、网速等信息。收费。

    +

    通过这个软件,我可以直观地查看我跑程序的时候 CPU 有没有全部用上,它在状态栏并不会占用太多空间,下载东西的时候也可以监控网速。

    +

    DaisyDisk

    +

    这是一个非常好用的磁盘空间整理工具,你可以检查你的 Mac 上占用空间较大的文件都在哪里。收费。

    +

    DaisyDisk

    +

    虚拟机

    +

    Parallels Desktop

    +

    这是一款非常优秀的虚拟机软件,收费。

    +

    它创新的融合模式可以让你在 Mac 桌面下,在使用 Windows 软件的时候感觉像在使用 Mac 原生的软件,比如:

    +

    CoherenceViewmode

    +

    后面的窗口是 Finder,前面的窗口是一个 Windows 应用,使用 Parallels Desktop 可以让你无缝使用 Mac 和 Windows 的应用。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/offline-python-environment/index.html b/offline-python-environment/index.html new file mode 100644 index 0000000..cb966f0 --- /dev/null +++ b/offline-python-environment/index.html @@ -0,0 +1,1440 @@ + + + + + + + + + + + + + + + + + + + + + + + 离线安装 Python 环境 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + + + + +
    +
    + + + + + + + +

    离线 Python 环境

    +

    有时因为限制,我们不能够在目标机器上使用网络安装 Python 环境,那么如何离线构建 Anaconda 虚拟环境,以及如何离线安装各种 Python 库,就是一个必须要思考的问题。我会在这篇文章里介绍我在离线安装 Anaconda 和配置 Python 环境方面的一些经验。

    +

    离线构建 Python 环境的构建需要:

    +

    在有网的机器上:

    +
      +
    • 下载服务器对应的 conda 安装包
    • +
    • 下载 Python 虚拟环境 pkg 文件
    • +
    • 下载 Python 库的 whl 文件
    • +
    +

    在离线服务器上:

    +
      +
    • 安装 conda
    • +
    • 安装 Python 虚拟环境
    • +
    • 安装 Python 库
    • +
    +

    提示:

    +
      +
    • 如果离线服务器已经安装 conda,可以不用重复安装
    • +
    • 如果离线服务器已经有你需要的 Python 版本对应的虚拟环境,可以使用 conda create --clone 克隆旧的虚拟环境
    • +
    +

    下载 conda 安装包

    +

    如果你使用的 Python 版本是 Python 3.7,那么直接下载最新的 Anaconda 即可,自带 Python 3.7 以及许多机器学习环境,只需要离线安装一些深度学习库,这部分内容可以参考下面的下载whl文件。

    +

    如果你使用 Python 3.7 以下的版本,如 Python 3.6,那么你可以只下载 Miniconda,然后通过 pkg 里先安装你想要的Python 版本。为什么不下载 Anaconda 呢?因为它很大,而且里面的 Python 版本并不是我们需要的版本。

    +

    目前最新的 Anaconda 和 Miniconda 下载链接:

    +
      +
    • https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh
    • +
    • https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
    • +
    +

    如果你遇到了网络问题,可以使用清华大学开源软件镜像站的 Anaconda 镜像

    +
      +
    • https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.07-Linux-x86_64.sh
    • +
    • https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh
    • +
    +

    可以使用下面的命令来下载:

    +
    mkdir -p ~/Downloads/offline
    +cd ~/Downloads/offline
    +wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh
    +
    + + + +

    下载 pkg 文件和 whl 文件

    +

    pip download 可以下载你所需要和依赖的 Python 库对应的 whl 安装包,但是你必须确保系统内核和 Python 版本一致。如果你使用的是 Mac,而目标机器是 Linux,那么你就不能够使用 pip download 命令很方便地下载所有依赖的 whl 文件。为了简化这一问题,我们可以使用 Docker 创建一个 Linux 环境来完成下载任务。

    +

    启动 miniconda 容器

    +

    通过 -v 参数,我们可以将 Docker 内部的 /data 路径和本地的 ~/Downloads/offline 路径链接起来,这样当我们下载到 /data 时,就可以在本机的 ~/Downloads/offline 文件夹里看到。

    +
    docker run -it -v ~/Downloads/offline:/data -w /data continuumio/miniconda
    +
    + +

    添加 conda 源(可选)

    +

    通过添加清华大学开源软件镜像站的 Anaconda 镜像,我们可以加速下载过程。

    +
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
    +conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
    +conda config --set show_channel_urls yes
    +
    + +

    下载 pkg 文件

    +

    Anaconda 所有的库都是通过 pkg 安装的,我们只要下载这些 pkg 文件,即可创建我们想要的环境。

    +

    首先删除 miniconda docker 里已有的 pkg 文件,因为 miniconda 默认安装了 Python 2.7,我们不希望在安装 Python 3.6 的时候有 Python 2.7 的 pkg 文件。

    +

    然后我们创建一个 Python 3.6 环境。如果你希望安装 Python 的其他版本,可以在创建环境的时候自行修改版本号。

    +

    创建好环境以后,所有需要的 pkg 文件(后缀名是 .tar.bz2)就会下载到 /opt/conda/pkgs 目录下,我们只需要把它们拷到 /data 目录下,即可在本机的下载文件夹里看见。

    +
    rm -rf /opt/conda/pkgs
    +
    +conda create -n ypw python=3.6
    +source activate ypw
    +
    +mkdir -p /data/pkgs
    +cd /opt/conda/pkgs
    +cp *.tar.bz2 /data/pkgs
    +
    + + + +

    配置 pip 源(可选)

    +

    通过添加清华大学开源软件镜像站的 Pypi 镜像,我们可以加速下载过程。

    +
    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
    +
    + +

    下载 whl 文件

    +

    whl 文件就是我们常说的 Python 库的安装文件,下面是我常用的 Python 库,你可以根据自己的需要进行修改。

    +
    mkdir -p /data/whls
    +cd /data/whls
    +pip download jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx
    +
    + + + +

    在离线机器上进行离线安装

    +

    将离线包传到离线机器上

    +

    下载好所有需要的离线安装包以后,我们就需要将它们传到离线服务器上,然后逐个安装。如果你的机器不支持rsync 命令,可以使用 scp 命令。

    +
    rsync -avP ~/Downloads/offline fat:~/
    +
    + +

    安装 conda

    +

    安装 conda 直接使用 bash 运行,然后按照提示进行即可。

    +
    bash ~/offline/Miniconda3-latest-Linux-x86_64.sh
    +
    + + + +

    创建 Python 虚拟环境

    +

    先创建一个空环境,然后安装已经下载好的 pkg 文件,你就可以离线创建一个 Python 3.6 的环境。

    +
    conda create -n ypw --offline
    +source activate ypw
    +conda install --offline ~/offline/pkgs/*
    +
    + +

    安装 whl 库

    +

    最后,使用 pip 离线安装下载好的 whl 文件。

    +
    pip install --no-index --find-links=file:///home/richinfo/offline/whls jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx
    +
    + + + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python-environment/index.html b/python-environment/index.html new file mode 100644 index 0000000..7a89eb4 --- /dev/null +++ b/python-environment/index.html @@ -0,0 +1,2450 @@ + + + + + + + + + + + + + + + + + + + + + + + Python 环境 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + + + + +
    +
    + + + + + + + +

    Python 环境

    +

    对于深度学习工程师来说,Python 是必不可少的工具,因为大多数深度学习框架都支持 Python(比如 TensorFlow、PyTorch、MXNet 等)。在模型开发阶段,使用 Python 非常方便,如果配合 Jupyter Notebook 使用,还可以进一步提升开发效率。

    +

    Miniconda bash 安装

    +

    下载 最新的 miniconda 安装包。

    +

    20230424 下载的是 Miniconda3-latest-MacOSX-arm64.sh

    +

    命令行安装

    +
    # bash 安装包路径
    +bash /Users/lhy/Downloads/Miniconda3-latest-MacOSX-arm64.sh
    +
    + +

    安装 Miniconda 后,会自动将 Miniconda 的路径添加到环境变量中,但是需要关闭并重新打开 shell 才能生效。 +如果需要在当前终端会话中立即生效,可以使用以下命令:

    +
    source ~/.zshrc
    +
    + +

    Miniconda brew 安装

    +

    命令行安装

    +
    brew install --cask miniconda
    +
    + +

    此时,conda 会安装在这个路径下 /opt/homebrew/bin/conda

    +

    检查 miniconda 是否安装成功

    +
    conda --version
    +
    + +

    卸载 miniconda

    +
    rm -rf conda
    +
    + +

    Anaconda

    +

    Anaconda 是一个 Pyhton 的包管理器,它可以简化 Python 环境的安装。由于 Ubuntu 系统、macOS 系统的局限性,我们尽量不要在系统自带的环境里安装深度学习库,不然可能会出现一些不可预料的问题。

    +

    Anaconda 中的 numpy、scikit-learn 等库使用了 Intel MKL 进行加速,理论上会比 pip 直接安装的版本速度快。

    +

    Anaconda 不需要 root 权限,所以可以很方便地安装在用户目录下,只要配置好环境变量即可使用,当你不需要它的时候,只需要直接删除它的目录,然后将对应的环境变量一起删除即可。

    +

    你可以直接 rsync 整个 anaconda 文件夹到其他相同硬件和系统环境的机器上,它们的 Python 环境可以保持绝对的统一,在做分布式并行训练的时候非常有用。

    +

    安装 Anaconda

    +

    Anaconda 官方下载页面:https://www.anaconda.com/downloads

    +

    你只需要下载对应系统的安装包,然后直接运行安装包即可。

    +

    命令行安装

    +

    在 macOS 上安装 Anaconda 可以使用下面的命令:

    +
    wget https://repo.anaconda.com/archive/Anaconda3-2020.02-MacOSX-x86_64.sh
    +bash Anaconda3-2020.02-MacOSX-x86_64.sh
    +
    + + +

    brew cask 安装

    +

    macOS 上还可以使用 brew cask 安装

    +
    brew cask install Anaconda
    +
    + +

    配置环境变量

    +

    安装好以后,有可能需要手动配置环境变量,如果你使用的是 zsh,你需要为 zsh 初始化:

    +
    /usr/local/anaconda3/bin/conda init zsh
    +
    + +

    执行以后,在 ~/.zshrc 中可以看到下面的内容:

    +
    # >>> conda initialize >>>
    +# !! Contents within this block are managed by 'conda init' !!
    +__conda_setup="$('/home/ypw/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
    +if [ $? -eq 0 ]; then
    +    eval "$__conda_setup"
    +else
    +    if [ -f "/home/ypw/anaconda3/etc/profile.d/conda.sh" ]; then
    +        . "/home/ypw/anaconda3/etc/profile.d/conda.sh"
    +    else
    +        export PATH="/home/ypw/anaconda3/bin:$PATH"
    +    fi
    +fi
    +unset __conda_setup
    +# <<< conda initialize <<<
    +
    + +

    使用 Anaconda 创建其他 Python 环境

    +

    如果我们需要其他 Python 环境,可以使用 conda 创建:

    +
    conda create -n python2 python=2.7
    +source activate python2
    +
    + +

    参考链接:https://conda.io/docs/user-guide/tasks/manage-environments.html

    +

    把 Conda 的 Python 环境添加到 jupyter 里

    +

    当你希望在 jupyter 里使用你的虚拟环境的时候,你需要执行下面的命令:

    +
    conda activate python2
    +conda install ipykernel
    +python -m ipykernel install --user --name python2 --display-name "Python 2"
    +
    + +

    其中的 python2 是你的虚拟环境的名字,display-name 可以取一个好听的名字,它会在 jupyter notebook 切换 kernel 的地方显示。

    +

    参考链接:https://ipython.readthedocs.io/en/stable/install/kernel_install.html

    +

    切换 anaconda 源

    +

    如果遇到网络问题,可以使用清华大学的镜像

    +
    nano ~/.condarc
    +
    +# 添加下面的内容
    +channels:
    +  - defaults
    +show_channel_urls: true
    +default_channels:
    +  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
    +  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
    +  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
    +custom_channels:
    +  conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +  msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +  bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +  menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +  pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +  simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
    +
    + +

    切换 pip 源

    +

    如果遇到网络问题,可以使用阿里云的镜像:

    +
    pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
    +
    + +

    常用 pypi 镜像:

    +
      +
    • https://mirrors.aliyun.com/pypi/simple/
    • +
    • https://pypi.tuna.tsinghua.edu.cn/simple/
    • +
    • https://mirrors.163.com/pypi/simple/
    • +
    • https://pypi.doubanio.com/simple/
    • +
    • https://mirrors.ustc.edu.cn/pypi/web/simple/
    • +
    +

    Python 库

    +

    下面是我认为比较重要的 Python 库:

    +
      +
    • jupyter
    • +
    • jupyter_contrib_nbextensions
    • +
    • numpy
    • +
    • pandas
    • +
    • scikit-learn
    • +
    • matplotlib
    • +
    • opencv-python
    • +
    • pillow
    • +
    • tqdm
    • +
    • torch
    • +
    • torchvision
    • +
    • tensorflow
    • +
    • keras
    • +
    • tensorboard
    • +
    • tensorboardx
    • +
    +

    安装大礼包:

    +
    pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow keras tensorboardx xlrd openpyxl
    +
    + +

    jupyter

    +

    在实验阶段,强烈建议你使用 jupyter notebook 编写实验代码,因为它与写 Python 脚本的逻辑完全不同。

    +

    官方介绍:

    +
    +

    Jupyter Notebook是一个开源Web应用程序,允许您创建和共享包含实时代码,公式,可视化和叙述文本的文档。用途包括:数据清理和转换,数值模拟,统计建模,数据可视化,机器学习等。

    +
    +

    特点:

    +
      +
    • web页面交互,在各个平台甚至是手机上都有同样的界面
    • +
    • 运行过的代码产生的变量、函数、类不会消失,除非你重启内核
    • +
    • 不仅支持写代码,显示函数输出的文字,还支持显示图片,甚至实现简单的交互功能
    • +
    • 支持 Markdown 编写注释,还支持 latex 公式
    • +
    +

    jupyter_contrib_nbextensions

    +

    Jupyter Notebook 插件。

    +
    +

    jupyter_contrib_nbextensions软件包包含一系列社区贡献的非官方扩展,可为Jupyter笔记本添加功能。这些扩展大多是用Javascript编写的,将在您的浏览器中本地加载。

    +
    +

    我使用了代码执行时间插件函数折叠插件

    +

    numpy

    +

    科学计算必备库。

    +
    +

    NumPy是Python语言的一个扩展程序库。支持高端大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

    +
    +

    pandas

    +

    操作 csv 非常方便,python 里的 excel。

    +
    +

    _pandas_是一个开源的,BSD许可的库,为Python编程语言提供高性能,易于使用的数据结构和数据分析工具。

    +
    +

    scikit-learn

    +

    机器学习模型大全。

    +
    +

    Python中的机器学习

    +
      +
    • 简单有效的数据挖掘和数据分析工具
    • +
    • 可供所有人访问,并可在各种环境中重复使用
    • +
    • 基于NumPy,SciPy和matplotlib构建
    • +
    • 开源,商业上可用 - BSD许可证
    • +
    +
    +

    注意安装的时候不是 sklearn,而是 scikit-learn:

    +
    pip install scikit-learn
    +
    + +

    matplotlib

    +

    画图工具。

    +
    +

    Matplotlib是一个Python 2D绘图库,可以生成各种硬拷贝格式和跨平台的交互式环境的出版物质量数据。Matplotlib可用于Python脚本、IPython shell、Jupyter Notebook 和 Web应用程序服务器和四个图形用户界面工具包。

    +
    +

    opencv-python

    +

    OpenCV 的 Python 库,图像处理必备。注意这不是官方的库,而是第三方编译的库。

    +
    +

    OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。

    +
    +

    官方建议是从源码编译:https://docs.opencv.org/3.4.6/d2/de6/tutorial_py_setup_in_ubuntu.html

    +

    如果你使用的功能不是很复杂,那么你可以直接使用 pip 安装 opencv-python。如果你使用了 opencv-contrib 里的功能,可以安装 opencv-contrib-python

    +

    pillow

    +

    PIL,另一个图像处理库,PyTorch 里的 torchvision 有很多写好的数据增强类,它们的输入类型是 PIL.Image。

    +
    +

    该库提供广泛的文件格式支持,高效的内部表示和相当强大的图像处理功能。

    +

    核心图像库旨在快速访问以几种基本像素格式存储的数据。它应该为一般的图像处理工具提供坚实的基础。

    +
    +

    tqdm

    +

    进度条库,耗时长的任务可以使用 tqdm 直观地展示任务的进度,避免焦虑。

    +
    +

    tqdm在阿拉伯语中是“进步”(taqadum,تقدم)的意思,在西班牙语中是“我太爱你了”(te quiero demasiado)的缩写。

    +

    只需在任何迭代器外包一个 tqdm:tqdm(iterable),就能立刻让你的循环显示一个聪明的进度条!

    +
    +

    tqdm

    +

    torch

    +

    深度学习库,推荐使用。

    +
    +

    一个开源深度学习平台,提供从研究原型到生产部署的无缝路径。

    +
    +

    torchvision

    +

    和 PyTorch 配套使用。

    +
    +

    torchvision包含了流行的数据集,预训练模型和计算机视觉的常见的图像变换。

    +
    +

    tensorflow

    +

    深度学习库,大而全。配备显卡的机器请按照 Ubuntu 环境 进行配置。

    +
    +

    TensorFlow是一个用于机器学习的端到端开源平台。 它拥有全面、灵活的工具、库和社区资源生态系统,可让研究人员推动ML的最新技术,开发人员可轻松构建和部署ML驱动的应用程序。

    +
    +

    keras

    +

    更高级的 API,和 tensorflow 联合使用很方便。最新的 TensorFlow 2.0 非常推荐使用 Keras 作为模型搭建的高级 API,你不必直接安装 Keras,直接使用 tf.keras 即可。

    +
    +

    Keras是一个高级神经网络API,用Python编写,能够在TensorFlow,CNTK或Theano之上运行。它的开发重点是实现快速实验。能够以最小的延迟从理念到结果是进行良好研究的关键。

    +
    +

    绘制模型结构需要 graphviz 和 pydot。

    +

    tensorboard

    +

    TensorBoard 是一个可视化工具,你可以使用它可视化:

    +
      +
    • loss、acc 曲线
    • +
    • 模型结构
    • +
    • 权重分布
    • +
    • 生成的图像
    • +
    • 生成的文字
    • +
    +

    tensorboardX

    +

    tensorboardX 是一个框架无关的 tensorboard writer,支持 numpy 矩阵、pytorch 的 tensor 等格式。

    +

    目前 pytorch 1.1 也有官方支持,但是功能有限,所以目前我仍然在使用 tensorboardX。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/remote-debugging-with-pycharm/index.html b/remote-debugging-with-pycharm/index.html new file mode 100644 index 0000000..b9f6812 --- /dev/null +++ b/remote-debugging-with-pycharm/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + + + + + + + + + + + + + + + 如何使用 PyCharm 远程调试 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    + +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..46b2241 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u751f\u5b58\u6307\u5357 \u5728\u7ebf\u9605\u8bfb\uff1a https://dl.ypw.io \u5728\u7ebf\u9605\u8bfb\uff1a https://ypwhs.github.io/dl-engineer-guidebook/ \u9879\u76ee\u5730\u5740\uff1a https://github.com/ypwhs/dl-engineer-guidebook \u6301\u7eed\u5173\u6ce8\u8bf7\u70b9 Watch \u6536\u85cf\u9879\u76ee\u8bf7\u70b9 Star \u8d21\u732e\u5185\u5bb9\u8bf7\u70b9 Fork \u63d0\u95ee\u6216\u5efa\u8bae\u8bf7\u70b9 Issue \u672c\u4e66\u4f1a\u8bb2\u8ff0\u4e00\u4e2a\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6240\u9700\u7684\u6240\u6709\u4e1c\u897f\uff1a \u5982\u4f55\u914d\u7f6e\u4e00\u53f0\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9? CPU \u4e3b\u677f \u663e\u5361 \u786c\u76d8 \u5185\u5b58 \u7535\u6e90 \u7f51\u5361 \u673a\u7bb1 \u663e\u793a\u5668 \u952e\u76d8\u9f20\u6807 \u672c\u5730\u8bbe\u5907 Windows\u3001Linux \u8fd8\u662f macOS\uff1f Mac \u5bf9\u6bd4 \u5176\u4ed6 \u89e6\u63a7\u677f \u673a\u68b0\u952e\u76d8 iPad Pro \u8def\u7531\u5668 NAS \u79fb\u52a8\u786c\u76d8 U\u76d8 macOS \u8f6f\u4ef6 \u7ec8\u7aef \u7f16\u8f91\u5668 \u6d4f\u89c8\u5668 \u5f00\u53d1\u8f6f\u4ef6 \u5b9e\u7528\u5de5\u5177 \u865a\u62df\u673a macOS \u73af\u5883 Homebrew oh my zsh \u5fc5\u5907\u8f6f\u4ef6 \u7ec8\u7aef \u7f16\u8f91\u5668 \u6d4f\u89c8\u5668 \u5f00\u53d1\u8f6f\u4ef6 \u5b9e\u7528\u5de5\u5177 \u65e5\u5e38\u5e94\u7528 \u5fc5\u5907\u547d\u4ee4 Python \u73af\u5883 Anaconda Python \u5e93 Ubuntu \u88c5\u673a\u6b65\u9aa4 \u5b89\u88c5 Ubuntu \u914d\u7f6e ssh \u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90\uff08\u63a8\u8350\uff09 \u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4\uff08\u63a8\u8350\uff09 \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08\u5206\u4e3a apt \u548c run \u4e24\u79cd\u5b89\u88c5\u65b9\u5f0f\uff09 \u5b89\u88c5 Anaconda \u548c Python \u5e93 Ubuntu \u73af\u5883 CUDA cuDNN TensorFlow PyTorch \u5fc5\u5907\u547d\u4ee4 curl tmux \u4e0e iTerm2 \u7ed3\u5408\u4f7f\u7528 screen \u540e\u53f0\u8fd0\u884c\u547d\u4ee4 \u5e38\u7528 Linux \u547d\u4ee4 \u6587\u4ef6\u67e5\u770b \u6587\u4ef6\u8bfb\u5199 \u6253\u5305\u538b\u7f29 \u6743\u9650\u7ba1\u7406 \u8fdb\u7a0b\u7ba1\u7406 \u78c1\u76d8\u7ba1\u7406 \u7cfb\u7edf\u7ba1\u7406 \u7cfb\u7edf\u76d1\u6d4b \u7f51\u7edc\u901a\u4fe1 CV \u5b66\u4e60\u8d44\u6e90 \u516c\u5f00\u8bfe \u7f51\u7ad9 \u4e66\u7c4d \u5e38\u7528 CV \u6570\u636e\u96c6 \u6570\u636e\u96c6\u4f7f\u7528\u65b9\u6cd5 MNIST CIFAR ImageNet VOC COCO CelebA \u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u7ecf\u5178\u6a21\u578b \u9884\u8bad\u7ec3\u6a21\u578b\u4f7f\u7528\u65b9\u6cd5 TensorFlow PyTorch \u6a21\u578b\u8bba\u6587 \u5982\u4f55\u4f7f\u7528 TensorBoard \u5b89\u88c5 \u4f7f\u7528 \u521b\u5efa\u6587\u4ef6\u5bf9\u8c61\uff08writer\uff09 \u6253\u5f00 TensorBoard \u670d\u52a1 \u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784 \u8bb0\u5f55\u6807\u91cf\uff08scalar\uff09 \u8bb0\u5f55\u591a\u4e2a\u6807\u91cf\uff08scalars\uff09 \u8bb0\u5f55\u56fe\u50cf\uff08images\uff09 \u5b8c\u6574\u4ee3\u7801 \u603b\u7ed3 \u79bb\u7ebf Python \u73af\u5883 \u4e0b\u8f7d conda \u5b89\u88c5\u5305 \u4e0b\u8f7d pkg \u6587\u4ef6\u548c whl \u6587\u4ef6 \u542f\u52a8 miniconda \u5bb9\u5668 \u6dfb\u52a0 conda \u6e90\uff08\u53ef\u9009\uff09 \u4e0b\u8f7d pkg \u6587\u4ef6 \u914d\u7f6e pip \u6e90\uff08\u53ef\u9009\uff09 \u4e0b\u8f7d whl \u6587\u4ef6 \u5728\u79bb\u7ebf\u673a\u5668\u4e0a\u8fdb\u884c\u5b89\u88c5 \u5c06\u79bb\u7ebf\u5305\u4f20\u5230\u79bb\u7ebf\u673a\u5668\u4e0a \u5b89\u88c5 conda \u521b\u5efa Python \u865a\u62df\u73af\u5883 \u5b89\u88c5 whl \u5e93","title":"\u9996\u9875"},{"location":"#_1","text":"\u5728\u7ebf\u9605\u8bfb\uff1a https://dl.ypw.io \u5728\u7ebf\u9605\u8bfb\uff1a https://ypwhs.github.io/dl-engineer-guidebook/ \u9879\u76ee\u5730\u5740\uff1a https://github.com/ypwhs/dl-engineer-guidebook \u6301\u7eed\u5173\u6ce8\u8bf7\u70b9 Watch \u6536\u85cf\u9879\u76ee\u8bf7\u70b9 Star \u8d21\u732e\u5185\u5bb9\u8bf7\u70b9 Fork \u63d0\u95ee\u6216\u5efa\u8bae\u8bf7\u70b9 Issue \u672c\u4e66\u4f1a\u8bb2\u8ff0\u4e00\u4e2a\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6240\u9700\u7684\u6240\u6709\u4e1c\u897f\uff1a \u5982\u4f55\u914d\u7f6e\u4e00\u53f0\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9? CPU \u4e3b\u677f \u663e\u5361 \u786c\u76d8 \u5185\u5b58 \u7535\u6e90 \u7f51\u5361 \u673a\u7bb1 \u663e\u793a\u5668 \u952e\u76d8\u9f20\u6807 \u672c\u5730\u8bbe\u5907 Windows\u3001Linux \u8fd8\u662f macOS\uff1f Mac \u5bf9\u6bd4 \u5176\u4ed6 \u89e6\u63a7\u677f \u673a\u68b0\u952e\u76d8 iPad Pro \u8def\u7531\u5668 NAS \u79fb\u52a8\u786c\u76d8 U\u76d8 macOS \u8f6f\u4ef6 \u7ec8\u7aef \u7f16\u8f91\u5668 \u6d4f\u89c8\u5668 \u5f00\u53d1\u8f6f\u4ef6 \u5b9e\u7528\u5de5\u5177 \u865a\u62df\u673a macOS \u73af\u5883 Homebrew oh my zsh \u5fc5\u5907\u8f6f\u4ef6 \u7ec8\u7aef \u7f16\u8f91\u5668 \u6d4f\u89c8\u5668 \u5f00\u53d1\u8f6f\u4ef6 \u5b9e\u7528\u5de5\u5177 \u65e5\u5e38\u5e94\u7528 \u5fc5\u5907\u547d\u4ee4 Python \u73af\u5883 Anaconda Python \u5e93 Ubuntu \u88c5\u673a\u6b65\u9aa4 \u5b89\u88c5 Ubuntu \u914d\u7f6e ssh \u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90\uff08\u63a8\u8350\uff09 \u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4\uff08\u63a8\u8350\uff09 \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08\u5206\u4e3a apt \u548c run \u4e24\u79cd\u5b89\u88c5\u65b9\u5f0f\uff09 \u5b89\u88c5 Anaconda \u548c Python \u5e93 Ubuntu \u73af\u5883 CUDA cuDNN TensorFlow PyTorch \u5fc5\u5907\u547d\u4ee4 curl tmux \u4e0e iTerm2 \u7ed3\u5408\u4f7f\u7528 screen \u540e\u53f0\u8fd0\u884c\u547d\u4ee4 \u5e38\u7528 Linux \u547d\u4ee4 \u6587\u4ef6\u67e5\u770b \u6587\u4ef6\u8bfb\u5199 \u6253\u5305\u538b\u7f29 \u6743\u9650\u7ba1\u7406 \u8fdb\u7a0b\u7ba1\u7406 \u78c1\u76d8\u7ba1\u7406 \u7cfb\u7edf\u7ba1\u7406 \u7cfb\u7edf\u76d1\u6d4b \u7f51\u7edc\u901a\u4fe1 CV \u5b66\u4e60\u8d44\u6e90 \u516c\u5f00\u8bfe \u7f51\u7ad9 \u4e66\u7c4d \u5e38\u7528 CV \u6570\u636e\u96c6 \u6570\u636e\u96c6\u4f7f\u7528\u65b9\u6cd5 MNIST CIFAR ImageNet VOC COCO CelebA \u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u7ecf\u5178\u6a21\u578b \u9884\u8bad\u7ec3\u6a21\u578b\u4f7f\u7528\u65b9\u6cd5 TensorFlow PyTorch \u6a21\u578b\u8bba\u6587 \u5982\u4f55\u4f7f\u7528 TensorBoard \u5b89\u88c5 \u4f7f\u7528 \u521b\u5efa\u6587\u4ef6\u5bf9\u8c61\uff08writer\uff09 \u6253\u5f00 TensorBoard \u670d\u52a1 \u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784 \u8bb0\u5f55\u6807\u91cf\uff08scalar\uff09 \u8bb0\u5f55\u591a\u4e2a\u6807\u91cf\uff08scalars\uff09 \u8bb0\u5f55\u56fe\u50cf\uff08images\uff09 \u5b8c\u6574\u4ee3\u7801 \u603b\u7ed3 \u79bb\u7ebf Python \u73af\u5883 \u4e0b\u8f7d conda \u5b89\u88c5\u5305 \u4e0b\u8f7d pkg \u6587\u4ef6\u548c whl \u6587\u4ef6 \u542f\u52a8 miniconda \u5bb9\u5668 \u6dfb\u52a0 conda \u6e90\uff08\u53ef\u9009\uff09 \u4e0b\u8f7d pkg \u6587\u4ef6 \u914d\u7f6e pip \u6e90\uff08\u53ef\u9009\uff09 \u4e0b\u8f7d whl \u6587\u4ef6 \u5728\u79bb\u7ebf\u673a\u5668\u4e0a\u8fdb\u884c\u5b89\u88c5 \u5c06\u79bb\u7ebf\u5305\u4f20\u5230\u79bb\u7ebf\u673a\u5668\u4e0a \u5b89\u88c5 conda \u521b\u5efa Python \u865a\u62df\u73af\u5883 \u5b89\u88c5 whl \u5e93","title":"\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u751f\u5b58\u6307\u5357"},{"location":"best-models-on-imagenet/","text":"\u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u7ecf\u5178\u6a21\u578b ImageNet \u662f\u7531\u674e\u98de\u98de\u4e3b\u5bfc\u5efa\u7acb\u7684\u4e00\u4e2a\u8d85\u5927\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u6570\u636e\u96c6\u3002\u57fa\u4e8e\u6b64\u6570\u636e\u96c6\uff0c\u81ea 2010 \u5e74\u81f3 2017 \u5e74\u4e3e\u529e ImageNet \u6311\u6218\u8d5b\uff0c\u5373 ImageNet Large Scale Visual Recognition Challenge (ILSVRC)\u3002\u8fd9\u7bc7\u6587\u7ae0\u4ee5\u65f6\u95f4\u987a\u5e8f\u8bb0\u5f55\u4e86\u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u6a21\u578b\uff0c\u5f88\u591a\u4e5f\u662f ILSVRC \u4e0a\u7684\u51a0\u519b\u3002 \u9884\u8bad\u7ec3\u6a21\u578b\u4f7f\u7528\u65b9\u6cd5 TensorFlow https://www.tensorflow.org/tutorials/images/transfer_learning https://keras.io/api/applications/ PyTorch https://pytorch.org/vision/stable/models.html https://github.com/rwightman/pytorch-image-models https://pytorch.org/hub https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html \u6a21\u578b\u8bba\u6587 \u53c2\u8003\u94fe\u63a5\uff1a https://paperswithcode.com/sota/image-classification-on-imagenet VGG Very Deep Convolutional Networks for Large-Scale Image Recognition https://arxiv.org/abs/1409.1556 Submitted on 4 Sep 2014 ResNet Deep Residual Learning for Image Recognition https://arxiv.org/abs/1512.03385 Submitted on 10 Dec 2015 InceptionV3 Rethinking the Inception Architecture for Computer Vision https://arxiv.org/abs/1512.00567 Submitted on 2 Dec 2015 InceptionResNetV2 Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning https://arxiv.org/abs/1602.07261 Submitted on 23 Feb 2016 DenseNet Densely Connected Convolutional Networks https://arxiv.org/abs/1608.06993 Submitted on 25 Aug 2016 Xception Xception: Deep Learning with Depthwise Separable Convolutions https://arxiv.org/abs/1610.02357 Submitted on 7 Oct 2016 NASNet Neural Architecture Search with Reinforcement Learning https://arxiv.org/abs/1611.01578 Submitted on 5 Nov 2016 EfficientNet EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks https://arxiv.org/abs/1905.11946 Submitted on 28 May 2019","title":"\u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u7ecf\u5178\u6a21\u578b"},{"location":"best-models-on-imagenet/#imagenet","text":"ImageNet \u662f\u7531\u674e\u98de\u98de\u4e3b\u5bfc\u5efa\u7acb\u7684\u4e00\u4e2a\u8d85\u5927\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u6570\u636e\u96c6\u3002\u57fa\u4e8e\u6b64\u6570\u636e\u96c6\uff0c\u81ea 2010 \u5e74\u81f3 2017 \u5e74\u4e3e\u529e ImageNet \u6311\u6218\u8d5b\uff0c\u5373 ImageNet Large Scale Visual Recognition Challenge (ILSVRC)\u3002\u8fd9\u7bc7\u6587\u7ae0\u4ee5\u65f6\u95f4\u987a\u5e8f\u8bb0\u5f55\u4e86\u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u6a21\u578b\uff0c\u5f88\u591a\u4e5f\u662f ILSVRC \u4e0a\u7684\u51a0\u519b\u3002","title":"\u5728 ImageNet \u4e0a\u8868\u73b0\u51fa\u8272\u7684\u7ecf\u5178\u6a21\u578b"},{"location":"best-models-on-imagenet/#_1","text":"","title":"\u9884\u8bad\u7ec3\u6a21\u578b\u4f7f\u7528\u65b9\u6cd5"},{"location":"best-models-on-imagenet/#tensorflow","text":"https://www.tensorflow.org/tutorials/images/transfer_learning https://keras.io/api/applications/","title":"TensorFlow"},{"location":"best-models-on-imagenet/#pytorch","text":"https://pytorch.org/vision/stable/models.html https://github.com/rwightman/pytorch-image-models https://pytorch.org/hub https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html","title":"PyTorch"},{"location":"best-models-on-imagenet/#_2","text":"\u53c2\u8003\u94fe\u63a5\uff1a https://paperswithcode.com/sota/image-classification-on-imagenet","title":"\u6a21\u578b\u8bba\u6587"},{"location":"best-models-on-imagenet/#vgg","text":"Very Deep Convolutional Networks for Large-Scale Image Recognition https://arxiv.org/abs/1409.1556 Submitted on 4 Sep 2014","title":"VGG "},{"location":"best-models-on-imagenet/#resnet","text":"Deep Residual Learning for Image Recognition https://arxiv.org/abs/1512.03385 Submitted on 10 Dec 2015","title":"ResNet "},{"location":"best-models-on-imagenet/#inceptionv3","text":"Rethinking the Inception Architecture for Computer Vision https://arxiv.org/abs/1512.00567 Submitted on 2 Dec 2015","title":"InceptionV3 "},{"location":"best-models-on-imagenet/#inceptionresnetv2","text":"Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning https://arxiv.org/abs/1602.07261 Submitted on 23 Feb 2016","title":"InceptionResNetV2 "},{"location":"best-models-on-imagenet/#densenet","text":"Densely Connected Convolutional Networks https://arxiv.org/abs/1608.06993 Submitted on 25 Aug 2016","title":"DenseNet "},{"location":"best-models-on-imagenet/#xception","text":"Xception: Deep Learning with Depthwise Separable Convolutions https://arxiv.org/abs/1610.02357 Submitted on 7 Oct 2016","title":"Xception "},{"location":"best-models-on-imagenet/#nasnet","text":"Neural Architecture Search with Reinforcement Learning https://arxiv.org/abs/1611.01578 Submitted on 5 Nov 2016","title":"NASNet "},{"location":"best-models-on-imagenet/#efficientnet","text":"EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks https://arxiv.org/abs/1905.11946 Submitted on 28 May 2019","title":"EfficientNet"},{"location":"cv-dataset/","text":"\u5e38\u7528 CV \u6570\u636e\u96c6 \u8ba1\u7b97\u673a\u89c6\u89c9\u65b9\u9762\u5e38\u7528\u7684\u6570\u636e\u96c6\u3002 \u6570\u636e\u96c6\u4f7f\u7528\u65b9\u6cd5 TensorFlow https://www.tensorflow.org/datasets/datasets https://www.tensorflow.org/api_docs/python/tf/keras/datasets PyTorch https://pytorch.org/docs/stable/torchvision/datasets.html MNIST MNIST \u662f\u4e00\u4e2a\u624b\u5199\u6570\u5b57\u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c660000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 10 \u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u662f\u5c3a\u5bf8\u4e3a (28, 28) \u7684\u9ed1\u767d\u56fe\u3002 CIFAR CIFAR-10 \u662f\u4e00\u4e2a\u5f69\u8272\u56fe\u50cf\u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c6 60000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 10 \u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u662f\u5c3a\u5bf8\u4e3a (32, 32) \u7684\u5f69\u56fe\u3002 \u6b64\u5916\u8fd8\u6709 CIFAR-100 \u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c6\u6709 60000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 100\u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u4e5f\u662f (32, 32) \u7684\u5f69\u56fe\u3002 ImageNet ImageNet \u662f\u4e00\u4e2a\u628a\u6df1\u5ea6\u5b66\u4e60\u63a8\u5411\u4e00\u4e2a\u65b0\u7684\u9ad8\u5ea6\u7684\u6570\u636e\u96c6\uff0c\u975e\u5e38\u91cd\u8981\u3002 ImageNet 2012 \u8bad\u7ec3\u96c6\u5171\u6709\u7ea6 120\u4e07\u5f20\u56fe\u50cf\uff0c\u9a8c\u8bc1\u96c6\u6709 50000\u5f20\uff0c\u56fe\u50cf\u5c3a\u5bf8\u5404\u4e0d\u76f8\u540c\uff0c\u5728\u4f7f\u7528\u7684\u65f6\u5019\u901a\u5e38\u4f1a\u7ecf\u8fc7\u7f29\u653e\u548c\u968f\u673a\u88c1\u526a\u5904\u7406\u4e3a\u76f8\u540c\u5c3a\u5bf8\u7684\u6b63\u65b9\u5f62\u56fe\u7247\u3002 VGG\u3001ResNet \u548c DenseNet \u7684\u9ed8\u8ba4\u56fe\u50cf\u5c3a\u5bf8\u4e3a 224\uff0cInception \u662f 299 \uff0cNASNet \u662f 331\uff0c\u6700\u65b0\u7684 EfficientNet \u4f7f\u7528\u4e86\u4ece 224 \u5230 600 \u7684\u4e0d\u540c\u5c3a\u5bf8\u3002\u5c3a\u5bf8\u8d8a\u5927\u7684\u540c\u65f6\u4e5f\u4f1a\u4f7f\u7cbe\u5ea6\u8d8a\u9ad8\u3002 VOC VOC \u7684\u5168\u79f0\u662f The PASCAL Visual Object Classes Challenge\uff0c\u8be5\u6570\u636e\u96c6\u7684\u6807\u6ce8\u5f88\u4e30\u5bcc\uff0c\u53ef\u4ee5\u7528\u4e8e\u68c0\u6d4b\u548c\u5206\u5272\u7b49\u4efb\u52a1\u3002\u8be5\u6570\u636e\u96c6\u5171\u6709 20\u4e2a\u7c7b\u522b\u3002\u5728 YOLOv3 \u7684\u8bad\u7ec3\u4e2d\uff0c\u4f7f\u7528\u4e86 VOC 2007 \u5230 VOC 2012 \u7684\u6240\u6709\u6570\u636e\u3002 VOC 2007 \u6709 9963 \u5f20\u56fe\u50cf\uff0c\u5176\u4e2d\u8bad\u7ec3\u96c6 2501 \u5f20\uff0c\u9a8c\u8bc1\u96c62510 \u5f20\uff0c\u6d4b\u8bd5\u96c6 4952 \u5f20\u3002 COCO COCO \u5168\u79f0\u662f Common Objects in Context\uff0c\u662f\u4e00\u4e2a\u5927\u89c4\u6a21\u68c0\u6d4b\u3001\u5206\u5272\u3001\u5173\u952e\u70b9\u548c\u770b\u56fe\u8bf4\u8bdd\u6570\u636e\u96c6\u3002\u6570\u636e\u96c6\u6709 80 \u4e2a\u7c7b\u522b\u3002 COCO 2014 \u8bad\u7ec3\u96c6\u6709 83k \u5f20\u56fe\uff0c\u9a8c\u8bc1\u96c6\u6709 41k\uff0c\u6d4b\u8bd5\u96c6\u6709 41k\u3002 COCO 2015 \u6d4b\u8bd5\u96c6\u6709 81k\u3002 COCO 2017 \u8bad\u7ec3\u96c6\u6709 118k \uff0c\u9a8c\u8bc1\u96c6\u6709 5k\uff0c\u6d4b\u8bd5\u96c6\u6709 41k\u3002 CelebA CelebA \u5168\u79f0\u662f Large-scale CelebFaces Attributes (CelebA) Dataset\uff0c\u610f\u601d\u662f\u5927\u89c4\u6a21\u540d\u4eba\u9762\u90e8\u5c5e\u6027\u6570\u636e\u96c6\u3002\u6570\u636e\u96c6\u5171\u6709 202599\u5f20\u56fe\uff0c10117\u4f4d\u540d\u4eba\uff0c\u5c5e\u6027\u6709\u5934\u53d1\u3001\u7709\u6bdb\u3001\u773c\u775b\u3001\u9f3b\u5b50\u3001\u5634\u5df4\u3001\u8868\u60c5\u548c\u6027\u522b\u7b4940\u79cd\u5c5e\u6027\u3002\u6b64\u6570\u636e\u96c6\u53ef\u4ee5\u7528\u6765\u505a\u4eba\u8138\u8bc6\u522b\uff08\u5206\u7c7b\uff09\u3001\u4eba\u8138\u68c0\u6d4b\u3001\u4eba\u8138\u5173\u952e\u70b9\u68c0\u6d4b\u3001\u4eba\u8138 GAN \u7b49\u4efb\u52a1\u3002","title":"\u5e38\u7528 CV \u6570\u636e\u96c6"},{"location":"cv-dataset/#cv","text":"\u8ba1\u7b97\u673a\u89c6\u89c9\u65b9\u9762\u5e38\u7528\u7684\u6570\u636e\u96c6\u3002","title":"\u5e38\u7528 CV \u6570\u636e\u96c6"},{"location":"cv-dataset/#_1","text":"","title":"\u6570\u636e\u96c6\u4f7f\u7528\u65b9\u6cd5"},{"location":"cv-dataset/#tensorflow","text":"https://www.tensorflow.org/datasets/datasets https://www.tensorflow.org/api_docs/python/tf/keras/datasets","title":"TensorFlow"},{"location":"cv-dataset/#pytorch","text":"https://pytorch.org/docs/stable/torchvision/datasets.html","title":"PyTorch"},{"location":"cv-dataset/#mnist","text":"MNIST \u662f\u4e00\u4e2a\u624b\u5199\u6570\u5b57\u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c660000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 10 \u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u662f\u5c3a\u5bf8\u4e3a (28, 28) \u7684\u9ed1\u767d\u56fe\u3002","title":"MNIST"},{"location":"cv-dataset/#cifar","text":"CIFAR-10 \u662f\u4e00\u4e2a\u5f69\u8272\u56fe\u50cf\u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c6 60000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 10 \u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u662f\u5c3a\u5bf8\u4e3a (32, 32) \u7684\u5f69\u56fe\u3002 \u6b64\u5916\u8fd8\u6709 CIFAR-100 \u6570\u636e\u96c6\uff0c\u8bad\u7ec3\u96c6\u6709 60000\u5f20\uff0c\u6d4b\u8bd5\u96c6 10000\u5f20\uff0c\u5171\u6709 100\u4e2a\u7c7b\u522b\uff0c\u56fe\u50cf\u4e5f\u662f (32, 32) \u7684\u5f69\u56fe\u3002","title":"CIFAR"},{"location":"cv-dataset/#imagenet","text":"ImageNet \u662f\u4e00\u4e2a\u628a\u6df1\u5ea6\u5b66\u4e60\u63a8\u5411\u4e00\u4e2a\u65b0\u7684\u9ad8\u5ea6\u7684\u6570\u636e\u96c6\uff0c\u975e\u5e38\u91cd\u8981\u3002 ImageNet 2012 \u8bad\u7ec3\u96c6\u5171\u6709\u7ea6 120\u4e07\u5f20\u56fe\u50cf\uff0c\u9a8c\u8bc1\u96c6\u6709 50000\u5f20\uff0c\u56fe\u50cf\u5c3a\u5bf8\u5404\u4e0d\u76f8\u540c\uff0c\u5728\u4f7f\u7528\u7684\u65f6\u5019\u901a\u5e38\u4f1a\u7ecf\u8fc7\u7f29\u653e\u548c\u968f\u673a\u88c1\u526a\u5904\u7406\u4e3a\u76f8\u540c\u5c3a\u5bf8\u7684\u6b63\u65b9\u5f62\u56fe\u7247\u3002 VGG\u3001ResNet \u548c DenseNet \u7684\u9ed8\u8ba4\u56fe\u50cf\u5c3a\u5bf8\u4e3a 224\uff0cInception \u662f 299 \uff0cNASNet \u662f 331\uff0c\u6700\u65b0\u7684 EfficientNet \u4f7f\u7528\u4e86\u4ece 224 \u5230 600 \u7684\u4e0d\u540c\u5c3a\u5bf8\u3002\u5c3a\u5bf8\u8d8a\u5927\u7684\u540c\u65f6\u4e5f\u4f1a\u4f7f\u7cbe\u5ea6\u8d8a\u9ad8\u3002","title":"ImageNet"},{"location":"cv-dataset/#voc","text":"VOC \u7684\u5168\u79f0\u662f The PASCAL Visual Object Classes Challenge\uff0c\u8be5\u6570\u636e\u96c6\u7684\u6807\u6ce8\u5f88\u4e30\u5bcc\uff0c\u53ef\u4ee5\u7528\u4e8e\u68c0\u6d4b\u548c\u5206\u5272\u7b49\u4efb\u52a1\u3002\u8be5\u6570\u636e\u96c6\u5171\u6709 20\u4e2a\u7c7b\u522b\u3002\u5728 YOLOv3 \u7684\u8bad\u7ec3\u4e2d\uff0c\u4f7f\u7528\u4e86 VOC 2007 \u5230 VOC 2012 \u7684\u6240\u6709\u6570\u636e\u3002 VOC 2007 \u6709 9963 \u5f20\u56fe\u50cf\uff0c\u5176\u4e2d\u8bad\u7ec3\u96c6 2501 \u5f20\uff0c\u9a8c\u8bc1\u96c62510 \u5f20\uff0c\u6d4b\u8bd5\u96c6 4952 \u5f20\u3002","title":"VOC"},{"location":"cv-dataset/#coco","text":"COCO \u5168\u79f0\u662f Common Objects in Context\uff0c\u662f\u4e00\u4e2a\u5927\u89c4\u6a21\u68c0\u6d4b\u3001\u5206\u5272\u3001\u5173\u952e\u70b9\u548c\u770b\u56fe\u8bf4\u8bdd\u6570\u636e\u96c6\u3002\u6570\u636e\u96c6\u6709 80 \u4e2a\u7c7b\u522b\u3002 COCO 2014 \u8bad\u7ec3\u96c6\u6709 83k \u5f20\u56fe\uff0c\u9a8c\u8bc1\u96c6\u6709 41k\uff0c\u6d4b\u8bd5\u96c6\u6709 41k\u3002 COCO 2015 \u6d4b\u8bd5\u96c6\u6709 81k\u3002 COCO 2017 \u8bad\u7ec3\u96c6\u6709 118k \uff0c\u9a8c\u8bc1\u96c6\u6709 5k\uff0c\u6d4b\u8bd5\u96c6\u6709 41k\u3002","title":"COCO"},{"location":"cv-dataset/#celeba","text":"CelebA \u5168\u79f0\u662f Large-scale CelebFaces Attributes (CelebA) Dataset\uff0c\u610f\u601d\u662f\u5927\u89c4\u6a21\u540d\u4eba\u9762\u90e8\u5c5e\u6027\u6570\u636e\u96c6\u3002\u6570\u636e\u96c6\u5171\u6709 202599\u5f20\u56fe\uff0c10117\u4f4d\u540d\u4eba\uff0c\u5c5e\u6027\u6709\u5934\u53d1\u3001\u7709\u6bdb\u3001\u773c\u775b\u3001\u9f3b\u5b50\u3001\u5634\u5df4\u3001\u8868\u60c5\u548c\u6027\u522b\u7b4940\u79cd\u5c5e\u6027\u3002\u6b64\u6570\u636e\u96c6\u53ef\u4ee5\u7528\u6765\u505a\u4eba\u8138\u8bc6\u522b\uff08\u5206\u7c7b\uff09\u3001\u4eba\u8138\u68c0\u6d4b\u3001\u4eba\u8138\u5173\u952e\u70b9\u68c0\u6d4b\u3001\u4eba\u8138 GAN \u7b49\u4efb\u52a1\u3002","title":"CelebA"},{"location":"cv-resources/","text":"CV \u5b66\u4e60\u8d44\u6e90 \u8fd9\u91cc\u8bb0\u5f55\u4e86\u4e3a\u6211\u63d0\u4f9b\u4e86\u975e\u5e38\u591a\u5e2e\u52a9\u7684\u5b66\u4e60\u8d44\u6e90\u3002 \u516c\u5f00\u8bfe Coursera https://www.coursera.org/learn/machine-learning https://www.coursera.org/specializations/deep-learning \u5434\u6069\u8fbe\u7684\u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u7684\u8bfe\u7a0b\u662f\u5927\u90e8\u5206\u4eba\u7684\u5165\u95e8\u8bfe\u7a0b\uff0c\u5f53\u7136\u4e5f\u662f\u6211\u7684\u5165\u95e8\u8bfe\u7a0b\u3002 \u5982\u679c\u5728\u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u65b9\u9762\uff0c\u4f60\u662f\u96f6\u57fa\u7840\u6216\u8005\u57fa\u7840\u5341\u5206\u8584\u5f31\u7684\uff0c\u90a3\u4e48\u63a8\u8350\u4f60\u5b66\u4e60\u8fd9\u95e8\u8bfe\u7a0b\uff0c\u5e76\u5b8c\u6210\u91cc\u9762\u7684\u4ee3\u7801\u548c\u4f5c\u4e1a\u4efb\u52a1\u3002\u5f53\u4f60\u5b66\u5b8c\u8fd9\u95e8\u8bfe\u5c31\u5177\u6709\u4e86\u4e00\u5b9a\u7684\u57fa\u7840\uff0c\u53ef\u80fd\u4f1a\u5728\u66f4\u7ec6\u81f4\u7684\u9886\u57df\u8fdb\u884c\u7814\u7a76\uff0c\u6bd4\u5982\u8ba1\u7b97\u673a\u89c6\u89c9\u6216\u8005\u81ea\u7136\u8bed\u8a00\u5904\u7406\u3002 CS231n \u5982\u679c\u4f60\u611f\u5174\u8da3\u7684\u9886\u57df\u662f\u8ba1\u7b97\u673a\u89c6\u89c9\uff0c\u90a3\u4e48\u65af\u5766\u798f\u5927\u5b66\u7684 CS231n \u8bfe\u7a0b\u662f\u4e0d\u80fd\u9519\u8fc7\u7684\uff0c\u8fd9\u662f\u6211\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u5165\u95e8\u8bfe\u7a0b\uff0c\u6211\u7b2c\u4e00\u6b21\u4ece\u8fd9\u91cc\u5b66\u4f1a\u5e76\u7406\u89e3\u5377\u79ef\u7684\u57fa\u672c\u6982\u5ff5\u3002 \u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u7684\u8bed\u8a00\u4ee5 Python \u4e3a\u4e3b\uff0c\u5982\u679c\u9700\u8981\u5165\u95e8\u548c\u7ec3\u4e60 Python\uff0c\u8fd9\u4e2a\u8bfe\u7a0b\u4e2d\u4e5f\u63d0\u4f9b\u4e86\u975e\u5e38\u4f18\u79c0\u7684\u5b66\u4e60\u8d44\u6e90\u3002 @\u7231\u53ef\u53ef-\u7231\u751f\u6d3b @\u7231\u53ef\u53ef-\u7231\u751f\u6d3b \u662f\u5317\u4eac\u90ae\u7535\u5927\u5b66\u7684\u8001\u5e08\u7684\u5fae\u535a\u8d26\u6237\uff0c\u6bcf\u5929\u4f1a\u53d1\u5e03\u6700\u65b0\u7684\u8bba\u6587\u548c GitHub \u4f18\u79c0\u9879\u76ee\u7b49\uff0c\u53ef\u4ee5\u901a\u8fc7\u5b83\u5173\u6ce8\u673a\u5668\u5b66\u4e60\u9886\u57df\u6700\u65b0\u7814\u7a76\u6210\u679c\u3002 \u540c\u65f6\uff0c\u5b83\u7684\u54d4\u54e9\u54d4\u54e9\u8d26\u53f7 fly51fly \u4e0b\u6536\u5f55\u4e86\u975e\u5e38\u591a\u7684\u4f18\u79c0\u516c\u5f00\u8bfe\uff0c\u6bd4\u5982\u65af\u5766\u798f 2019 \u6700\u65b0\u7684\u81ea\u7136\u8bed\u8a00\u7406\u89e3\u8bfe\u7a0b\u3002\u5f53\u4f60\u5bf9\u77e5\u8bc6\u611f\u5230\u9965\u6e34\u65f6\u5c31\u53ef\u4ee5\u6765\u8fd9\u91cc\u5145\u7535\u3002 \u7f51\u7ad9 paperswithcode \u8fd9\u4e2a\u7f51\u7ad9\u603b\u7ed3\u4e86\u5f53\u524d\u6709\u5f00\u6e90\u4ee3\u7801\u7684\u8bba\u6587\uff0c\u4ee5\u53ca\u5b83\u4eec\u5728\u5404\u9879\u7ade\u8d5b\u4e0a\u7684\u8868\u73b0\u3002 \u6bd4\u5982\u8fd9\u4e2a\u9875\u9762\u53ef\u4ee5\u67e5\u770b ImageNet \u4e0a\u6700\u597d\u7684\u6a21\u578b\u6392\u540d\uff1a https://paperswithcode.com/sota/image-classification-on-imagenet \u4e66\u7c4d \u673a\u5668\u5b66\u4e60 \u673a\u5668\u5b66\u4e60\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u4e0e\u4eba\u5de5\u667a\u80fd\u7684\u91cd\u8981\u5206\u652f\u9886\u57df. \u672c\u4e66\u4f5c\u4e3a\u8be5\u9886\u57df\u7684\u5165\u95e8\u6559\u6750\uff0c\u5728\u5185\u5bb9\u4e0a\u5c3d\u53ef\u80fd\u6db5\u76d6\u673a\u5668\u5b66\u4e60\u57fa\u7840\u77e5\u8bc6\u7684\u5404\u65b9\u9762\u3002 \u4e3a\u4e86\u4f7f\u5c3d\u53ef\u80fd\u591a\u7684\u8bfb\u8005\u901a\u8fc7\u672c\u4e66\u5bf9\u673a\u5668\u5b66\u4e60\u6709\u6240\u4e86\u89e3, \u4f5c\u8005\u8bd5\u56fe\u5c3d\u53ef\u80fd\u5c11\u5730\u4f7f\u7528\u6570\u5b66\u77e5\u8bc6. \u7136\u800c, \u5c11\u91cf\u7684\u6982\u7387\u3001\u7edf\u8ba1\u3001\u4ee3\u6570\u3001\u4f18\u5316\u3001\u903b\u8f91\u77e5\u8bc6\u4f3c\u4e4e\u4e0d\u53ef\u907f\u514d. \u56e0\u6b64, \u672c\u4e66\u66f4\u9002\u5408\u5927\u5b66\u4e09\u5e74\u7ea7\u4ee5\u4e0a\u7684\u7406\u5de5\u79d1\u672c\u79d1\u751f\u548c\u7814\u7a76\u751f, \u4ee5\u53ca\u5177\u6709\u7c7b\u4f3c\u80cc\u666f\u7684\u5bf9\u673a\u5668\u5b66 \u4e60\u611f\u5174\u8da3\u7684\u4eba\u58eb. \u4e3a\u65b9\u4fbf\u8bfb\u8005, \u672c\u4e66\u9644\u5f55\u7ed9\u51fa\u4e86\u4e00\u4e9b\u76f8\u5173\u6570\u5b66\u57fa\u7840\u77e5\u8bc6\u7b80\u4ecb. \u5168\u4e66\u517116 \u7ae0\uff0c\u5927\u81f4\u5206\u4e3a3 \u4e2a\u90e8\u5206\uff1a\u7b2c1 \u90e8\u5206\uff08\u7b2c1\uff5e3 \u7ae0\uff09\u4ecb\u7ecd\u673a\u5668\u5b66\u4e60\u7684\u57fa\u7840\u77e5\u8bc6\uff1b\u7b2c2 \u90e8\u5206\uff08\u7b2c4\uff5e10 \u7ae0\uff09\u8ba8\u8bba\u4e00\u4e9b\u7ecf\u5178\u800c\u5e38\u7528\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff08\u51b3\u7b56\u6811\u3001\u795e\u7ecf\u7f51\u7edc\u3001\u652f\u6301\u5411\u91cf\u673a\u3001\u8d1d\u53f6\u65af\u5206\u7c7b\u5668\u3001\u96c6\u6210\u5b66\u4e60\u3001\u805a\u7c7b\u3001\u964d\u7ef4\u4e0e\u5ea6\u91cf\u5b66\u4e60\uff09\uff1b\u7b2c3 \u90e8\u5206\uff08\u7b2c11\uff5e16 \u7ae0\uff09\u4e3a\u8fdb\u9636\u77e5\u8bc6\uff0c\u5185\u5bb9\u6d89\u53ca\u7279\u5f81\u9009\u62e9\u4e0e\u7a00\u758f\u5b66\u4e60\u3001\u8ba1\u7b97\u5b66\u4e60\u7406\u8bba\u3001\u534a\u76d1\u7763\u5b66\u4e60\u3001\u6982\u7387\u56fe\u6a21\u578b\u3001\u89c4\u5219\u5b66\u4e60\u4ee5\u53ca\u5f3a\u5316\u5b66\u4e60\u7b49.\u524d3\u7ae0\u4e4b\u5916\u7684\u540e\u7eed\u5404\u7ae0\u5747\u76f8\u5bf9\u72ec\u7acb, \u8bfb\u8005\u53ef\u6839\u636e\u81ea\u5df1\u7684\u5174\u8da3\u548c\u65f6\u95f4\u60c5\u51b5\u9009\u62e9\u4f7f\u7528. \u6839\u636e\u8bfe\u65f6\u60c5\u51b5, \u4e00\u4e2a\u5b66\u671f\u7684\u672c\u79d1\u751f\u8bfe\u7a0b\u53ef\u8003\u8651\u8bb2\u6388\u524d9\u7ae0\u6216\u524d10\u7ae0; \u7814\u7a76\u751f\u8bfe\u7a0b\u5219\u4e0d\u59a8\u4f7f\u7528\u5168\u4e66. \u4e66\u4e2d\u9664\u7b2c1\u7ae0\u5916, \u6bcf\u7ae0\u90fd\u7ed9\u51fa\u4e86\u5341\u9053\u4e60\u9898. \u6709\u7684\u4e60\u9898\u662f\u5e2e\u52a9\u8bfb\u8005\u5de9\u56fa\u672c\u7ae0\u5b66\u4e60, \u6709\u7684\u662f\u4e3a\u4e86\u5f15\u5bfc\u8bfb\u8005\u6269\u5c55\u76f8\u5173\u77e5\u8bc6. \u4e00\u5b66\u671f\u7684\u4e00\u822c\u8bfe\u7a0b\u53ef\u4f7f\u7528\u8fd9\u4e9b\u4e60\u9898, \u518d\u8f85\u4ee5\u4e24\u5230\u4e09\u4e2a\u9488\u5bf9\u5177\u4f53\u6570\u636e\u96c6\u7684\u5927\u4f5c\u4e1a. \u5e26\u661f\u53f7\u7684\u4e60\u9898\u5219\u6709\u76f8\u5f53\u96be\u5ea6, \u6709\u4e9b\u5e76\u65e0\u73b0\u6210\u7b54\u6848, \u8c28\u4f9b\u5bcc\u6709\u8fdb\u53d6\u5fc3\u7684\u8bfb\u8005\u542f\u53d1\u601d\u8003. \u672c\u4e66\u53ef\u4f5c\u4e3a\u9ad8\u7b49\u9662\u6821\u8ba1\u7b97\u673a\u3001\u81ea\u52a8\u5316\u53ca\u76f8\u5173\u4e13\u4e1a\u7684\u672c\u79d1\u751f\u6216\u7814\u7a76\u751f\u6559\u6750\uff0c\u4e5f\u53ef\u4f9b\u5bf9\u673a\u5668\u5b66\u4e60\u611f\u5174\u8da3\u7684\u7814\u7a76\u4eba\u5458\u548c\u5de5\u7a0b\u6280\u672f\u4eba\u5458\u9605\u8bfb\u53c2\u8003\u3002 \u6b64\u4e66\u662f\u6211\u5165\u95e8\u673a\u5668\u5b66\u4e60\u7684\u65f6\u5019\u8ba4\u771f\u770b\u8fc7\u7684\uff0c\u5bf9\u6211\u7684\u5e2e\u52a9\u5f88\u5927\uff0c\u5efa\u8bae\u5927\u5bb6\u4ed4\u7ec6\u9605\u8bfb\u3002 \u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5 \u6df1\u5ea6\u5b66\u4e60\uff0c\u7279\u522b\u662f\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u662f\u4eba\u5de5\u667a\u80fd\u7684\u91cd\u8981\u5206\u652f\u9886\u57df\uff0c\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u6280\u672f\u4e5f\u88ab\u5e7f\u6cdb\u5e94\u7528\u4e8e\u5404\u79cd\u73b0\u5b9e\u573a\u666f\uff0c\u5728\u8bb8\u591a\u95ee\u9898\u4e0a\u90fd\u53d6\u5f97\u4e86\u8d85\u8d8a\u4eba\u7c7b\u667a\u80fd\u7684\u7ed3\u679c\u3002\u672c\u4e66\u4f5c\u4e3a\u8be5\u9886\u57df\u7684\u5165\u95e8\u4e66\u7c4d\uff0c\u5728\u5185\u5bb9\u4e0a\u6db5\u76d6\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7684\u57fa\u7840\u77e5\u8bc6\u548c\u5b9e\u8df5\u5e94\u7528\u4e24\u5927\u65b9\u9762\u3002\u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u517114 \u7ae0\uff0c\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7b2c\u4e00\u90e8\u5206\u4e3a\u7eea\u8bba\uff1b\u7b2c\u4e8c\u90e8\u5206 \uff08\u7b2c1\uff5e4 \u7ae0\uff09\u4ecb\u7ecd\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7684\u57fa\u7840\u77e5\u8bc6\u3001\u57fa\u672c\u90e8\u4ef6\u3001\u7ecf\u5178\u7ed3\u6784\u548c\u6a21\u578b\u538b\u7f29\u7b49\u57fa\u7840\u7406\u8bba\u5185\u5bb9\uff1b\u7b2c\u4e09\u90e8\u5206\uff08\u7b2c5\uff5e14 \u7ae0\uff09\u4ecb\u7ecd\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u81ea\u6570\u636e\u51c6\u5907\u5f00\u59cb\uff0c\u5230\u6a21\u578b\u53c2\u6570\u521d\u59cb\u5316\u3001\u4e0d\u540c\u7f51\u7edc\u90e8\u4ef6\u7684\u9009\u62e9\u3001\u7f51\u7edc\u914d\u7f6e\u3001\u7f51\u7edc\u6a21\u578b\u8bad\u7ec3\u3001\u4e0d\u5e73\u8861\u6570\u636e\u5904\u7406\uff0c\u6700\u7ec8\u5230\u6a21\u578b\u96c6\u6210\u7b49\u5b9e\u8df5\u5e94\u7528\u6280\u5de7\u548c\u7ecf\u9a8c\u3002\u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u5e76\u4e0d\u662f\u4e00\u672c\u7f16\u7a0b\u7c7b\u4e66\u7c4d\uff0c\u800c\u662f\u5e0c\u671b\u901a\u8fc7\u201c\u57fa\u7840\u77e5\u8bc6\u201d\u548c\u201c\u5b9e\u8df5\u6280\u5de7\u201d\u4e24\u65b9\u9762\u4f7f\u8bfb\u8005\u4ece\u66f4\u9ad8\u7ef4\u5ea6\u4e86\u89e3\u3001\u638c\u63e1\u5e76\u6210\u529f\u6784\u5efa\u9488\u5bf9\u81ea\u8eab\u5e94\u7528\u95ee\u9898\u7684\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u3002 \u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u53ef\u4f5c\u4e3a\u6df1\u5ea6\u5b66\u4e60\u548c\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7231\u597d\u8005\u7684\u5165\u95e8\u4e66\u7c4d\uff0c\u4e5f\u53ef\u4f9b\u6ca1\u6709\u673a\u5668\u5b66\u4e60\u80cc\u666f\u4f46\u5e0c\u671b\u80fd\u5feb\u901f\u638c\u63e1\u8be5\u65b9\u9762\u77e5\u8bc6\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u5b9e\u9645\u95ee\u9898\u7684\u5404\u884c\u4ece\u4e1a\u8005\u9605\u8bfb\u53c2\u8003\u3002 \u5f00\u6e90\u7535\u5b50\u7248\uff1a http://lamda.nju.edu.cn/weixs/book/CNN_book.html \u6b64\u4e66\u8fd8\u662f\u7535\u5b50\u7248\u7684\u65f6\u5019\u6211\u5c31\u5df2\u7ecf\u5728\u770b\u4e86\uff0c\u5bf9\u4e8e\u5165\u95e8\u8ba1\u7b97\u673a\u89c6\u89c9\u65b9\u5411\u7684\u521d\u5b66\u8005\u6765\u8bf4\u6982\u5ff5\u8bb2\u5f97\u5f88\u900f\u5f7b\u3002 \u52a8\u624b\u5b66\u6df1\u5ea6\u5b66\u4e60 \u672c\u4e66\u65e8\u5728\u5411\u8bfb\u8005\u4ea4\u4ed8\u6709\u5173\u6df1\u5ea6\u5b66\u4e60\u7684\u4ea4\u4e92\u5f0f\u5b66\u4e60\u4f53\u9a8c\u3002\u4e66\u4e2d\u4e0d\u4ec5\u9610\u8ff0\u6df1\u5ea6\u5b66\u4e60\u7684\u7b97\u6cd5\u539f\u7406\uff0c\u8fd8\u6f14\u793a\u5b83\u4eec\u7684\u5b9e\u73b0\u548c\u8fd0\u884c\u3002\u4e0e\u4f20\u7edf\u56fe\u4e66\u4e0d\u540c\uff0c\u672c\u4e66\u7684\u6bcf\u4e00\u8282\u90fd\u662f\u4e00\u4e2a\u53ef\u4ee5\u4e0b\u8f7d\u5e76\u8fd0\u884c\u7684 Jupyter\u8bb0\u4e8b\u672c\uff0c\u5b83\u5c06\u6587\u5b57\u3001\u516c\u5f0f\u3001\u56fe\u50cf\u3001\u4ee3\u7801\u548c\u8fd0\u884c\u7ed3\u679c\u7ed3\u5408\u5728\u4e86\u4e00\u8d77\u3002\u6b64\u5916\uff0c\u8bfb\u8005\u8fd8\u53ef\u4ee5\u8bbf\u95ee\u5e76\u53c2\u4e0e\u4e66\u4e2d\u5185\u5bb9\u7684\u8ba8\u8bba\u3002 \u5168\u4e66\u7684\u5185\u5bb9\u5206\u4e3a3\u4e2a\u90e8\u5206\uff1a\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u6df1\u5ea6\u5b66\u4e60\u7684\u80cc\u666f\uff0c\u63d0\u4f9b\u9884\u5907\u77e5\u8bc6\uff0c\u5e76\u5305\u62ec\u6df1\u5ea6\u5b66\u4e60\u6700\u57fa\u7840\u7684\u6982\u5ff5\u548c\u6280\u672f\uff1b\u7b2c\u4e8c\u90e8\u5206\u63cf\u8ff0\u6df1\u5ea6\u5b66\u4e60\u8ba1\u7b97\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\uff0c\u8fd8\u89e3\u91ca\u8fd1\u5e74\u6765\u4ee4\u6df1\u5ea6\u5b66\u4e60\u5728\u591a\u4e2a\u9886\u57df\u5927\u83b7\u6210\u529f\u7684\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u548c\u5faa\u73af\u795e\u7ecf\u7f51\u7edc\uff1b\u7b2c\u4e09\u90e8\u5206\u8bc4\u4ef7\u4f18\u5316\u7b97\u6cd5\uff0c\u68c0\u9a8c\u5f71\u54cd\u6df1\u5ea6\u5b66\u4e60\u8ba1\u7b97\u6027\u80fd\u7684\u91cd\u8981\u56e0\u7d20\uff0c\u5e76\u5206\u522b\u5217\u4e3e\u6df1\u5ea6\u5b66\u4e60\u5728\u8ba1\u7b97\u673a\u89c6\u89c9\u548c\u81ea\u7136\u8bed\u8a00\u5904\u7406\u4e2d\u7684\u91cd\u8981\u5e94\u7528\u3002 \u672c\u4e66\u540c\u65f6\u8986\u76d6\u6df1\u5ea6\u5b66\u4e60\u7684\u65b9\u6cd5\u548c\u5b9e\u8df5\uff0c\u4e3b\u8981\u9762\u5411\u5728\u6821\u5927\u5b66\u751f\u3001\u6280\u672f\u4eba\u5458\u548c\u7814\u7a76\u4eba\u5458\u3002\u9605\u8bfb\u672c\u4e66\u9700\u8981\u8bfb\u8005\u4e86\u89e3\u57fa\u672c\u7684Python\u7f16\u7a0b\u6216\u9644\u5f55\u4e2d\u63cf\u8ff0\u7684\u7ebf\u6027\u4ee3\u6570\u3001\u5fae\u5206\u548c\u6982\u7387\u57fa\u7840\u3002 \u5b98\u65b9\u7f51\u7ad9\uff1a https://zh.d2l.ai \u89c6\u9891\u8bfe\u7a0b\uff1a https://space.bilibili.com/209599371/channel/detail?cid=23541 \u6b64\u4e66\u8fd8\u5728\u7f16\u5199\u7684\u65f6\u5019\uff0c\u6211\u6b63\u5728\u505a\u4e00\u4e2a\u72d7\u5206\u7c7b\u7684 Kaggle \u7ade\u8d5b\uff0c\u7136\u540e\u5173\u6ce8\u5230 Gluon \u8bba\u575b\u6b63\u5728\u4ee5 kaggle \u4e0a\u7684\u6392\u540d\u6765\u53d1\u653e\u4e91\u670d\u52a1\u4ee3\u91d1\u5238\uff0c\u4e8e\u662f\u6211\u5c31 \u53c2\u52a0\u4e86 \u3002\u7136\u540e\u7248\u4e3b\u95ee\u6211\u6709\u6ca1\u6709\u5174\u8da3 \u5199\u4e00\u4e2a gluon \u7248\u7684 \uff0c\u6211\u5c31 \u7528 gluon \u5199\u4e86\u4e00\u4e2a \uff0c\u540e\u6765\u5c31\u5728\u8bba\u575b\u548c\u5927\u5bb6 \u4e00\u8d77\u4e92\u52a8 \uff0c\u5b66\u5230\u4e86\u8bb8\u591a\u4e1c\u897f\uff0c\u6210\u4e3a\u4e86\u8bba\u575b\u7684\u7248\u4e3b\u3002\u4e4b\u540e\u6b64\u4e66\u4e0d\u65ad\u5b8c\u5584\uff0c\u6211\u4e5f\u8d21\u732e\u4e86\u81ea\u5df1\u7684\u4e00\u4efd\u529b\u91cf\u3002\u51fa\u7248\u540e\uff0c\u6211\u62ff\u5230\u4e86\u8d21\u732e\u8005\u4e13\u4eab\u7684\u300a\u52a8\u624b\u5b66\u6df1\u5ea6\u5b66\u4e60\u300b\u3002 \u5982\u679c\u4f60\u60f3\u4f7f\u7528 Gluon\uff0c\u8fd9\u672c\u4e66\u5728\u5408\u9002\u4e0d\u8fc7\u4e86\u3002\u5373\u4f7f\u4f60\u4e0d\u7528 Gluon\uff0c\u6b64\u4e66\u4f9d\u7136\u53ef\u4ee5\u7ed9\u4f60\u8bb8\u591a\u5165\u95e8\u7684\u6982\u5ff5\uff0c\u4ece\u6700\u57fa\u7840\u7684\u77e9\u9635\u8fd0\u7b97\uff0c\u5230\u5206\u7c7b\u3001\u68c0\u6d4b\u3001\u5206\u5272\u548c\u98ce\u683c\u8fc1\u79fb\u7b49\uff0c\u503c\u5f97\u4e00\u770b\u3002\u56e0\u4e3a\u4e66\u4e2d\u6709\u5927\u91cf\u7684\u4ee3\u7801\u3001\u56fe\u7247\u3001\u56fe\u8868\uff0c\u5efa\u8bae\u8d2d\u4e70\u5168\u5f69\u7cbe\u88c5\u7248\u3002 \u6df1\u5ea6\u5b66\u4e60\u6280\u672f\u56fe\u50cf\u5904\u7406\u5165\u95e8 \u672c\u4e66\u4ece\u673a\u5668\u5b66\u4e60\u3001\u56fe\u50cf\u5904\u7406\u7684\u57fa\u672c\u6982\u5ff5\u5165\u624b\uff0c\u9010\u6b65\u9610\u8ff0\u6df1\u5ea6\u5b66\u4e60\u56fe\u50cf\u5904\u7406\u6280\u672f\u7684\u57fa\u672c\u539f\u7406\u4ee5\u53ca\u7b80\u5355\u7684\u5b9e\u73b0\u3002\u7ee7\u800c\u4ee5\u51e0\u4e2a\u5b9e\u6218\u6848\u4f8b\u6765\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528\u6df1\u5ea6\u5b66\u4e60\u65b9\u6cd5\uff0c\u5728\u6570\u636e\u5206\u6790\u7ade\u8d5b\u4e2d\u53d6\u5f97\u8f83\u9ad8\u7684\u6392\u540d\u3002\u6700\u540e\uff0c\u901a\u8fc7\u4e00\u4e2a\u5b9e\u6218\u6848\u4f8b\uff0c\u4ecb\u7ecd\u5982\u4f55\u5c06\u6a21\u578b\u653e\u5165 iOS \u7a0b\u5e8f\uff0c\u5236\u4f5c\u76f8\u5e94\u7684\u4eba\u5de5\u667a\u80fd\u624b\u673aApp\u3002 \u672c\u4e66\u9002\u7528\u4e8e\u5bf9\u6df1\u5ea6\u5b66\u4e60\u6709\u5174\u8da3\u3001\u5e0c\u671b\u5165\u95e8\u8fd9\u4e00\u9886\u57df\u7684\u7406\u5de5\u79d1\u5927\u5b66\u751f\u3001\u7814\u7a76\u751f\uff0c\u4ee5\u53ca\u5e0c\u671b\u4e86\u89e3\u8be5\u9886\u57df\u57fa\u672c\u539f\u7406\u7684\u8f6f\u4ef6\u5f00\u53d1\u4eba\u5458\u3002\u6b64\u5916\uff0c\u672c\u4e66\u6240\u6709\u6848\u4f8b\u5747\u63d0\u4f9b\u4e86\u4e91\u73af\u5883\u4e0a\u7684\u4ee3\u7801\uff0c\u4fbf\u4e8e\u8bfb\u8005\u590d\u73b0\u7ed3\u679c\uff0c\u5e76\u8fdb\u884c\u6df1\u5165\u5b66\u4e60\u3002 \u6b64\u4e66\u662f\u6211\u548c\u80e1\u535a\u5f3a\u4e00\u8d77\u5199\u7684\uff0c\u4e3b\u8981\u5185\u5bb9\u662f\u6df1\u5ea6\u5b66\u4e60\u3001\u56fe\u50cf\u5904\u7406\u5165\u95e8\uff0c\u4ee5\u53ca\u51e0\u4e2a\u57fa\u4e8e Keras \u7684\u9879\u76ee\u3002\u5982\u679c\u4f60\u5173\u6ce8\u4e86\u6211\u7684 github\uff0c\u90a3\u4e48\u6b64\u4e66\u662f\u4e0d\u9700\u8981\u4e70\u7684\uff0c\u56e0\u4e3a\u9879\u76ee\u5728 github \u4e0a\u90fd\u6709\uff1a \u732b\u72d7\u5927\u6218\uff1a https://github.com/ypwhs/dogs_vs_cats \u9a8c\u8bc1\u7801\u8bc6\u522b\uff1a https://github.com/ypwhs/captcha_break \u767e\u5ea6\u4e91\u9b45\u65cf\u6df1\u5ea6\u5b66\u4e60\u5e94\u7528\u5927\u8d5b\uff1a https://github.com/ypwhs/baiduyun_deeplearning_competition \u6df1\u5ea6\u5b66\u4e60 APP\uff1a https://github.com/ypwhs/CAM","title":"CV \u5b66\u4e60\u8d44\u6e90"},{"location":"cv-resources/#cv","text":"\u8fd9\u91cc\u8bb0\u5f55\u4e86\u4e3a\u6211\u63d0\u4f9b\u4e86\u975e\u5e38\u591a\u5e2e\u52a9\u7684\u5b66\u4e60\u8d44\u6e90\u3002","title":"CV \u5b66\u4e60\u8d44\u6e90"},{"location":"cv-resources/#_1","text":"","title":"\u516c\u5f00\u8bfe"},{"location":"cv-resources/#coursera","text":"https://www.coursera.org/learn/machine-learning https://www.coursera.org/specializations/deep-learning \u5434\u6069\u8fbe\u7684\u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u7684\u8bfe\u7a0b\u662f\u5927\u90e8\u5206\u4eba\u7684\u5165\u95e8\u8bfe\u7a0b\uff0c\u5f53\u7136\u4e5f\u662f\u6211\u7684\u5165\u95e8\u8bfe\u7a0b\u3002 \u5982\u679c\u5728\u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u65b9\u9762\uff0c\u4f60\u662f\u96f6\u57fa\u7840\u6216\u8005\u57fa\u7840\u5341\u5206\u8584\u5f31\u7684\uff0c\u90a3\u4e48\u63a8\u8350\u4f60\u5b66\u4e60\u8fd9\u95e8\u8bfe\u7a0b\uff0c\u5e76\u5b8c\u6210\u91cc\u9762\u7684\u4ee3\u7801\u548c\u4f5c\u4e1a\u4efb\u52a1\u3002\u5f53\u4f60\u5b66\u5b8c\u8fd9\u95e8\u8bfe\u5c31\u5177\u6709\u4e86\u4e00\u5b9a\u7684\u57fa\u7840\uff0c\u53ef\u80fd\u4f1a\u5728\u66f4\u7ec6\u81f4\u7684\u9886\u57df\u8fdb\u884c\u7814\u7a76\uff0c\u6bd4\u5982\u8ba1\u7b97\u673a\u89c6\u89c9\u6216\u8005\u81ea\u7136\u8bed\u8a00\u5904\u7406\u3002","title":"Coursera"},{"location":"cv-resources/#cs231n","text":"\u5982\u679c\u4f60\u611f\u5174\u8da3\u7684\u9886\u57df\u662f\u8ba1\u7b97\u673a\u89c6\u89c9\uff0c\u90a3\u4e48\u65af\u5766\u798f\u5927\u5b66\u7684 CS231n \u8bfe\u7a0b\u662f\u4e0d\u80fd\u9519\u8fc7\u7684\uff0c\u8fd9\u662f\u6211\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u5165\u95e8\u8bfe\u7a0b\uff0c\u6211\u7b2c\u4e00\u6b21\u4ece\u8fd9\u91cc\u5b66\u4f1a\u5e76\u7406\u89e3\u5377\u79ef\u7684\u57fa\u672c\u6982\u5ff5\u3002 \u673a\u5668\u5b66\u4e60\u548c\u6df1\u5ea6\u5b66\u4e60\u7684\u8bed\u8a00\u4ee5 Python \u4e3a\u4e3b\uff0c\u5982\u679c\u9700\u8981\u5165\u95e8\u548c\u7ec3\u4e60 Python\uff0c\u8fd9\u4e2a\u8bfe\u7a0b\u4e2d\u4e5f\u63d0\u4f9b\u4e86\u975e\u5e38\u4f18\u79c0\u7684\u5b66\u4e60\u8d44\u6e90\u3002","title":"CS231n"},{"location":"cv-resources/#-","text":"@\u7231\u53ef\u53ef-\u7231\u751f\u6d3b \u662f\u5317\u4eac\u90ae\u7535\u5927\u5b66\u7684\u8001\u5e08\u7684\u5fae\u535a\u8d26\u6237\uff0c\u6bcf\u5929\u4f1a\u53d1\u5e03\u6700\u65b0\u7684\u8bba\u6587\u548c GitHub \u4f18\u79c0\u9879\u76ee\u7b49\uff0c\u53ef\u4ee5\u901a\u8fc7\u5b83\u5173\u6ce8\u673a\u5668\u5b66\u4e60\u9886\u57df\u6700\u65b0\u7814\u7a76\u6210\u679c\u3002 \u540c\u65f6\uff0c\u5b83\u7684\u54d4\u54e9\u54d4\u54e9\u8d26\u53f7 fly51fly \u4e0b\u6536\u5f55\u4e86\u975e\u5e38\u591a\u7684\u4f18\u79c0\u516c\u5f00\u8bfe\uff0c\u6bd4\u5982\u65af\u5766\u798f 2019 \u6700\u65b0\u7684\u81ea\u7136\u8bed\u8a00\u7406\u89e3\u8bfe\u7a0b\u3002\u5f53\u4f60\u5bf9\u77e5\u8bc6\u611f\u5230\u9965\u6e34\u65f6\u5c31\u53ef\u4ee5\u6765\u8fd9\u91cc\u5145\u7535\u3002","title":"@\u7231\u53ef\u53ef-\u7231\u751f\u6d3b"},{"location":"cv-resources/#_2","text":"","title":"\u7f51\u7ad9"},{"location":"cv-resources/#paperswithcode","text":"\u8fd9\u4e2a\u7f51\u7ad9\u603b\u7ed3\u4e86\u5f53\u524d\u6709\u5f00\u6e90\u4ee3\u7801\u7684\u8bba\u6587\uff0c\u4ee5\u53ca\u5b83\u4eec\u5728\u5404\u9879\u7ade\u8d5b\u4e0a\u7684\u8868\u73b0\u3002 \u6bd4\u5982\u8fd9\u4e2a\u9875\u9762\u53ef\u4ee5\u67e5\u770b ImageNet \u4e0a\u6700\u597d\u7684\u6a21\u578b\u6392\u540d\uff1a https://paperswithcode.com/sota/image-classification-on-imagenet","title":"paperswithcode"},{"location":"cv-resources/#_3","text":"","title":"\u4e66\u7c4d"},{"location":"cv-resources/#_4","text":"\u673a\u5668\u5b66\u4e60\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u4e0e\u4eba\u5de5\u667a\u80fd\u7684\u91cd\u8981\u5206\u652f\u9886\u57df. \u672c\u4e66\u4f5c\u4e3a\u8be5\u9886\u57df\u7684\u5165\u95e8\u6559\u6750\uff0c\u5728\u5185\u5bb9\u4e0a\u5c3d\u53ef\u80fd\u6db5\u76d6\u673a\u5668\u5b66\u4e60\u57fa\u7840\u77e5\u8bc6\u7684\u5404\u65b9\u9762\u3002 \u4e3a\u4e86\u4f7f\u5c3d\u53ef\u80fd\u591a\u7684\u8bfb\u8005\u901a\u8fc7\u672c\u4e66\u5bf9\u673a\u5668\u5b66\u4e60\u6709\u6240\u4e86\u89e3, \u4f5c\u8005\u8bd5\u56fe\u5c3d\u53ef\u80fd\u5c11\u5730\u4f7f\u7528\u6570\u5b66\u77e5\u8bc6. \u7136\u800c, \u5c11\u91cf\u7684\u6982\u7387\u3001\u7edf\u8ba1\u3001\u4ee3\u6570\u3001\u4f18\u5316\u3001\u903b\u8f91\u77e5\u8bc6\u4f3c\u4e4e\u4e0d\u53ef\u907f\u514d. \u56e0\u6b64, \u672c\u4e66\u66f4\u9002\u5408\u5927\u5b66\u4e09\u5e74\u7ea7\u4ee5\u4e0a\u7684\u7406\u5de5\u79d1\u672c\u79d1\u751f\u548c\u7814\u7a76\u751f, \u4ee5\u53ca\u5177\u6709\u7c7b\u4f3c\u80cc\u666f\u7684\u5bf9\u673a\u5668\u5b66 \u4e60\u611f\u5174\u8da3\u7684\u4eba\u58eb. \u4e3a\u65b9\u4fbf\u8bfb\u8005, \u672c\u4e66\u9644\u5f55\u7ed9\u51fa\u4e86\u4e00\u4e9b\u76f8\u5173\u6570\u5b66\u57fa\u7840\u77e5\u8bc6\u7b80\u4ecb. \u5168\u4e66\u517116 \u7ae0\uff0c\u5927\u81f4\u5206\u4e3a3 \u4e2a\u90e8\u5206\uff1a\u7b2c1 \u90e8\u5206\uff08\u7b2c1\uff5e3 \u7ae0\uff09\u4ecb\u7ecd\u673a\u5668\u5b66\u4e60\u7684\u57fa\u7840\u77e5\u8bc6\uff1b\u7b2c2 \u90e8\u5206\uff08\u7b2c4\uff5e10 \u7ae0\uff09\u8ba8\u8bba\u4e00\u4e9b\u7ecf\u5178\u800c\u5e38\u7528\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff08\u51b3\u7b56\u6811\u3001\u795e\u7ecf\u7f51\u7edc\u3001\u652f\u6301\u5411\u91cf\u673a\u3001\u8d1d\u53f6\u65af\u5206\u7c7b\u5668\u3001\u96c6\u6210\u5b66\u4e60\u3001\u805a\u7c7b\u3001\u964d\u7ef4\u4e0e\u5ea6\u91cf\u5b66\u4e60\uff09\uff1b\u7b2c3 \u90e8\u5206\uff08\u7b2c11\uff5e16 \u7ae0\uff09\u4e3a\u8fdb\u9636\u77e5\u8bc6\uff0c\u5185\u5bb9\u6d89\u53ca\u7279\u5f81\u9009\u62e9\u4e0e\u7a00\u758f\u5b66\u4e60\u3001\u8ba1\u7b97\u5b66\u4e60\u7406\u8bba\u3001\u534a\u76d1\u7763\u5b66\u4e60\u3001\u6982\u7387\u56fe\u6a21\u578b\u3001\u89c4\u5219\u5b66\u4e60\u4ee5\u53ca\u5f3a\u5316\u5b66\u4e60\u7b49.\u524d3\u7ae0\u4e4b\u5916\u7684\u540e\u7eed\u5404\u7ae0\u5747\u76f8\u5bf9\u72ec\u7acb, \u8bfb\u8005\u53ef\u6839\u636e\u81ea\u5df1\u7684\u5174\u8da3\u548c\u65f6\u95f4\u60c5\u51b5\u9009\u62e9\u4f7f\u7528. \u6839\u636e\u8bfe\u65f6\u60c5\u51b5, \u4e00\u4e2a\u5b66\u671f\u7684\u672c\u79d1\u751f\u8bfe\u7a0b\u53ef\u8003\u8651\u8bb2\u6388\u524d9\u7ae0\u6216\u524d10\u7ae0; \u7814\u7a76\u751f\u8bfe\u7a0b\u5219\u4e0d\u59a8\u4f7f\u7528\u5168\u4e66. \u4e66\u4e2d\u9664\u7b2c1\u7ae0\u5916, \u6bcf\u7ae0\u90fd\u7ed9\u51fa\u4e86\u5341\u9053\u4e60\u9898. \u6709\u7684\u4e60\u9898\u662f\u5e2e\u52a9\u8bfb\u8005\u5de9\u56fa\u672c\u7ae0\u5b66\u4e60, \u6709\u7684\u662f\u4e3a\u4e86\u5f15\u5bfc\u8bfb\u8005\u6269\u5c55\u76f8\u5173\u77e5\u8bc6. \u4e00\u5b66\u671f\u7684\u4e00\u822c\u8bfe\u7a0b\u53ef\u4f7f\u7528\u8fd9\u4e9b\u4e60\u9898, \u518d\u8f85\u4ee5\u4e24\u5230\u4e09\u4e2a\u9488\u5bf9\u5177\u4f53\u6570\u636e\u96c6\u7684\u5927\u4f5c\u4e1a. \u5e26\u661f\u53f7\u7684\u4e60\u9898\u5219\u6709\u76f8\u5f53\u96be\u5ea6, \u6709\u4e9b\u5e76\u65e0\u73b0\u6210\u7b54\u6848, \u8c28\u4f9b\u5bcc\u6709\u8fdb\u53d6\u5fc3\u7684\u8bfb\u8005\u542f\u53d1\u601d\u8003. \u672c\u4e66\u53ef\u4f5c\u4e3a\u9ad8\u7b49\u9662\u6821\u8ba1\u7b97\u673a\u3001\u81ea\u52a8\u5316\u53ca\u76f8\u5173\u4e13\u4e1a\u7684\u672c\u79d1\u751f\u6216\u7814\u7a76\u751f\u6559\u6750\uff0c\u4e5f\u53ef\u4f9b\u5bf9\u673a\u5668\u5b66\u4e60\u611f\u5174\u8da3\u7684\u7814\u7a76\u4eba\u5458\u548c\u5de5\u7a0b\u6280\u672f\u4eba\u5458\u9605\u8bfb\u53c2\u8003\u3002 \u6b64\u4e66\u662f\u6211\u5165\u95e8\u673a\u5668\u5b66\u4e60\u7684\u65f6\u5019\u8ba4\u771f\u770b\u8fc7\u7684\uff0c\u5bf9\u6211\u7684\u5e2e\u52a9\u5f88\u5927\uff0c\u5efa\u8bae\u5927\u5bb6\u4ed4\u7ec6\u9605\u8bfb\u3002","title":"\u673a\u5668\u5b66\u4e60"},{"location":"cv-resources/#_5","text":"\u6df1\u5ea6\u5b66\u4e60\uff0c\u7279\u522b\u662f\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u662f\u4eba\u5de5\u667a\u80fd\u7684\u91cd\u8981\u5206\u652f\u9886\u57df\uff0c\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u6280\u672f\u4e5f\u88ab\u5e7f\u6cdb\u5e94\u7528\u4e8e\u5404\u79cd\u73b0\u5b9e\u573a\u666f\uff0c\u5728\u8bb8\u591a\u95ee\u9898\u4e0a\u90fd\u53d6\u5f97\u4e86\u8d85\u8d8a\u4eba\u7c7b\u667a\u80fd\u7684\u7ed3\u679c\u3002\u672c\u4e66\u4f5c\u4e3a\u8be5\u9886\u57df\u7684\u5165\u95e8\u4e66\u7c4d\uff0c\u5728\u5185\u5bb9\u4e0a\u6db5\u76d6\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7684\u57fa\u7840\u77e5\u8bc6\u548c\u5b9e\u8df5\u5e94\u7528\u4e24\u5927\u65b9\u9762\u3002\u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u517114 \u7ae0\uff0c\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7b2c\u4e00\u90e8\u5206\u4e3a\u7eea\u8bba\uff1b\u7b2c\u4e8c\u90e8\u5206 \uff08\u7b2c1\uff5e4 \u7ae0\uff09\u4ecb\u7ecd\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7684\u57fa\u7840\u77e5\u8bc6\u3001\u57fa\u672c\u90e8\u4ef6\u3001\u7ecf\u5178\u7ed3\u6784\u548c\u6a21\u578b\u538b\u7f29\u7b49\u57fa\u7840\u7406\u8bba\u5185\u5bb9\uff1b\u7b2c\u4e09\u90e8\u5206\uff08\u7b2c5\uff5e14 \u7ae0\uff09\u4ecb\u7ecd\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u81ea\u6570\u636e\u51c6\u5907\u5f00\u59cb\uff0c\u5230\u6a21\u578b\u53c2\u6570\u521d\u59cb\u5316\u3001\u4e0d\u540c\u7f51\u7edc\u90e8\u4ef6\u7684\u9009\u62e9\u3001\u7f51\u7edc\u914d\u7f6e\u3001\u7f51\u7edc\u6a21\u578b\u8bad\u7ec3\u3001\u4e0d\u5e73\u8861\u6570\u636e\u5904\u7406\uff0c\u6700\u7ec8\u5230\u6a21\u578b\u96c6\u6210\u7b49\u5b9e\u8df5\u5e94\u7528\u6280\u5de7\u548c\u7ecf\u9a8c\u3002\u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u5e76\u4e0d\u662f\u4e00\u672c\u7f16\u7a0b\u7c7b\u4e66\u7c4d\uff0c\u800c\u662f\u5e0c\u671b\u901a\u8fc7\u201c\u57fa\u7840\u77e5\u8bc6\u201d\u548c\u201c\u5b9e\u8df5\u6280\u5de7\u201d\u4e24\u65b9\u9762\u4f7f\u8bfb\u8005\u4ece\u66f4\u9ad8\u7ef4\u5ea6\u4e86\u89e3\u3001\u638c\u63e1\u5e76\u6210\u529f\u6784\u5efa\u9488\u5bf9\u81ea\u8eab\u5e94\u7528\u95ee\u9898\u7684\u6df1\u5ea6\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u3002 \u300a\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5\u300b\u53ef\u4f5c\u4e3a\u6df1\u5ea6\u5b66\u4e60\u548c\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u7231\u597d\u8005\u7684\u5165\u95e8\u4e66\u7c4d\uff0c\u4e5f\u53ef\u4f9b\u6ca1\u6709\u673a\u5668\u5b66\u4e60\u80cc\u666f\u4f46\u5e0c\u671b\u80fd\u5feb\u901f\u638c\u63e1\u8be5\u65b9\u9762\u77e5\u8bc6\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u5b9e\u9645\u95ee\u9898\u7684\u5404\u884c\u4ece\u4e1a\u8005\u9605\u8bfb\u53c2\u8003\u3002 \u5f00\u6e90\u7535\u5b50\u7248\uff1a http://lamda.nju.edu.cn/weixs/book/CNN_book.html \u6b64\u4e66\u8fd8\u662f\u7535\u5b50\u7248\u7684\u65f6\u5019\u6211\u5c31\u5df2\u7ecf\u5728\u770b\u4e86\uff0c\u5bf9\u4e8e\u5165\u95e8\u8ba1\u7b97\u673a\u89c6\u89c9\u65b9\u5411\u7684\u521d\u5b66\u8005\u6765\u8bf4\u6982\u5ff5\u8bb2\u5f97\u5f88\u900f\u5f7b\u3002","title":"\u89e3\u6790\u6df1\u5ea6\u5b66\u4e60\uff1a\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u539f\u7406\u4e0e\u89c6\u89c9\u5b9e\u8df5"},{"location":"cv-resources/#_6","text":"\u672c\u4e66\u65e8\u5728\u5411\u8bfb\u8005\u4ea4\u4ed8\u6709\u5173\u6df1\u5ea6\u5b66\u4e60\u7684\u4ea4\u4e92\u5f0f\u5b66\u4e60\u4f53\u9a8c\u3002\u4e66\u4e2d\u4e0d\u4ec5\u9610\u8ff0\u6df1\u5ea6\u5b66\u4e60\u7684\u7b97\u6cd5\u539f\u7406\uff0c\u8fd8\u6f14\u793a\u5b83\u4eec\u7684\u5b9e\u73b0\u548c\u8fd0\u884c\u3002\u4e0e\u4f20\u7edf\u56fe\u4e66\u4e0d\u540c\uff0c\u672c\u4e66\u7684\u6bcf\u4e00\u8282\u90fd\u662f\u4e00\u4e2a\u53ef\u4ee5\u4e0b\u8f7d\u5e76\u8fd0\u884c\u7684 Jupyter\u8bb0\u4e8b\u672c\uff0c\u5b83\u5c06\u6587\u5b57\u3001\u516c\u5f0f\u3001\u56fe\u50cf\u3001\u4ee3\u7801\u548c\u8fd0\u884c\u7ed3\u679c\u7ed3\u5408\u5728\u4e86\u4e00\u8d77\u3002\u6b64\u5916\uff0c\u8bfb\u8005\u8fd8\u53ef\u4ee5\u8bbf\u95ee\u5e76\u53c2\u4e0e\u4e66\u4e2d\u5185\u5bb9\u7684\u8ba8\u8bba\u3002 \u5168\u4e66\u7684\u5185\u5bb9\u5206\u4e3a3\u4e2a\u90e8\u5206\uff1a\u7b2c\u4e00\u90e8\u5206\u4ecb\u7ecd\u6df1\u5ea6\u5b66\u4e60\u7684\u80cc\u666f\uff0c\u63d0\u4f9b\u9884\u5907\u77e5\u8bc6\uff0c\u5e76\u5305\u62ec\u6df1\u5ea6\u5b66\u4e60\u6700\u57fa\u7840\u7684\u6982\u5ff5\u548c\u6280\u672f\uff1b\u7b2c\u4e8c\u90e8\u5206\u63cf\u8ff0\u6df1\u5ea6\u5b66\u4e60\u8ba1\u7b97\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\uff0c\u8fd8\u89e3\u91ca\u8fd1\u5e74\u6765\u4ee4\u6df1\u5ea6\u5b66\u4e60\u5728\u591a\u4e2a\u9886\u57df\u5927\u83b7\u6210\u529f\u7684\u5377\u79ef\u795e\u7ecf\u7f51\u7edc\u548c\u5faa\u73af\u795e\u7ecf\u7f51\u7edc\uff1b\u7b2c\u4e09\u90e8\u5206\u8bc4\u4ef7\u4f18\u5316\u7b97\u6cd5\uff0c\u68c0\u9a8c\u5f71\u54cd\u6df1\u5ea6\u5b66\u4e60\u8ba1\u7b97\u6027\u80fd\u7684\u91cd\u8981\u56e0\u7d20\uff0c\u5e76\u5206\u522b\u5217\u4e3e\u6df1\u5ea6\u5b66\u4e60\u5728\u8ba1\u7b97\u673a\u89c6\u89c9\u548c\u81ea\u7136\u8bed\u8a00\u5904\u7406\u4e2d\u7684\u91cd\u8981\u5e94\u7528\u3002 \u672c\u4e66\u540c\u65f6\u8986\u76d6\u6df1\u5ea6\u5b66\u4e60\u7684\u65b9\u6cd5\u548c\u5b9e\u8df5\uff0c\u4e3b\u8981\u9762\u5411\u5728\u6821\u5927\u5b66\u751f\u3001\u6280\u672f\u4eba\u5458\u548c\u7814\u7a76\u4eba\u5458\u3002\u9605\u8bfb\u672c\u4e66\u9700\u8981\u8bfb\u8005\u4e86\u89e3\u57fa\u672c\u7684Python\u7f16\u7a0b\u6216\u9644\u5f55\u4e2d\u63cf\u8ff0\u7684\u7ebf\u6027\u4ee3\u6570\u3001\u5fae\u5206\u548c\u6982\u7387\u57fa\u7840\u3002 \u5b98\u65b9\u7f51\u7ad9\uff1a https://zh.d2l.ai \u89c6\u9891\u8bfe\u7a0b\uff1a https://space.bilibili.com/209599371/channel/detail?cid=23541 \u6b64\u4e66\u8fd8\u5728\u7f16\u5199\u7684\u65f6\u5019\uff0c\u6211\u6b63\u5728\u505a\u4e00\u4e2a\u72d7\u5206\u7c7b\u7684 Kaggle \u7ade\u8d5b\uff0c\u7136\u540e\u5173\u6ce8\u5230 Gluon \u8bba\u575b\u6b63\u5728\u4ee5 kaggle \u4e0a\u7684\u6392\u540d\u6765\u53d1\u653e\u4e91\u670d\u52a1\u4ee3\u91d1\u5238\uff0c\u4e8e\u662f\u6211\u5c31 \u53c2\u52a0\u4e86 \u3002\u7136\u540e\u7248\u4e3b\u95ee\u6211\u6709\u6ca1\u6709\u5174\u8da3 \u5199\u4e00\u4e2a gluon \u7248\u7684 \uff0c\u6211\u5c31 \u7528 gluon \u5199\u4e86\u4e00\u4e2a \uff0c\u540e\u6765\u5c31\u5728\u8bba\u575b\u548c\u5927\u5bb6 \u4e00\u8d77\u4e92\u52a8 \uff0c\u5b66\u5230\u4e86\u8bb8\u591a\u4e1c\u897f\uff0c\u6210\u4e3a\u4e86\u8bba\u575b\u7684\u7248\u4e3b\u3002\u4e4b\u540e\u6b64\u4e66\u4e0d\u65ad\u5b8c\u5584\uff0c\u6211\u4e5f\u8d21\u732e\u4e86\u81ea\u5df1\u7684\u4e00\u4efd\u529b\u91cf\u3002\u51fa\u7248\u540e\uff0c\u6211\u62ff\u5230\u4e86\u8d21\u732e\u8005\u4e13\u4eab\u7684\u300a\u52a8\u624b\u5b66\u6df1\u5ea6\u5b66\u4e60\u300b\u3002 \u5982\u679c\u4f60\u60f3\u4f7f\u7528 Gluon\uff0c\u8fd9\u672c\u4e66\u5728\u5408\u9002\u4e0d\u8fc7\u4e86\u3002\u5373\u4f7f\u4f60\u4e0d\u7528 Gluon\uff0c\u6b64\u4e66\u4f9d\u7136\u53ef\u4ee5\u7ed9\u4f60\u8bb8\u591a\u5165\u95e8\u7684\u6982\u5ff5\uff0c\u4ece\u6700\u57fa\u7840\u7684\u77e9\u9635\u8fd0\u7b97\uff0c\u5230\u5206\u7c7b\u3001\u68c0\u6d4b\u3001\u5206\u5272\u548c\u98ce\u683c\u8fc1\u79fb\u7b49\uff0c\u503c\u5f97\u4e00\u770b\u3002\u56e0\u4e3a\u4e66\u4e2d\u6709\u5927\u91cf\u7684\u4ee3\u7801\u3001\u56fe\u7247\u3001\u56fe\u8868\uff0c\u5efa\u8bae\u8d2d\u4e70\u5168\u5f69\u7cbe\u88c5\u7248\u3002","title":"\u52a8\u624b\u5b66\u6df1\u5ea6\u5b66\u4e60"},{"location":"cv-resources/#_7","text":"\u672c\u4e66\u4ece\u673a\u5668\u5b66\u4e60\u3001\u56fe\u50cf\u5904\u7406\u7684\u57fa\u672c\u6982\u5ff5\u5165\u624b\uff0c\u9010\u6b65\u9610\u8ff0\u6df1\u5ea6\u5b66\u4e60\u56fe\u50cf\u5904\u7406\u6280\u672f\u7684\u57fa\u672c\u539f\u7406\u4ee5\u53ca\u7b80\u5355\u7684\u5b9e\u73b0\u3002\u7ee7\u800c\u4ee5\u51e0\u4e2a\u5b9e\u6218\u6848\u4f8b\u6765\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528\u6df1\u5ea6\u5b66\u4e60\u65b9\u6cd5\uff0c\u5728\u6570\u636e\u5206\u6790\u7ade\u8d5b\u4e2d\u53d6\u5f97\u8f83\u9ad8\u7684\u6392\u540d\u3002\u6700\u540e\uff0c\u901a\u8fc7\u4e00\u4e2a\u5b9e\u6218\u6848\u4f8b\uff0c\u4ecb\u7ecd\u5982\u4f55\u5c06\u6a21\u578b\u653e\u5165 iOS \u7a0b\u5e8f\uff0c\u5236\u4f5c\u76f8\u5e94\u7684\u4eba\u5de5\u667a\u80fd\u624b\u673aApp\u3002 \u672c\u4e66\u9002\u7528\u4e8e\u5bf9\u6df1\u5ea6\u5b66\u4e60\u6709\u5174\u8da3\u3001\u5e0c\u671b\u5165\u95e8\u8fd9\u4e00\u9886\u57df\u7684\u7406\u5de5\u79d1\u5927\u5b66\u751f\u3001\u7814\u7a76\u751f\uff0c\u4ee5\u53ca\u5e0c\u671b\u4e86\u89e3\u8be5\u9886\u57df\u57fa\u672c\u539f\u7406\u7684\u8f6f\u4ef6\u5f00\u53d1\u4eba\u5458\u3002\u6b64\u5916\uff0c\u672c\u4e66\u6240\u6709\u6848\u4f8b\u5747\u63d0\u4f9b\u4e86\u4e91\u73af\u5883\u4e0a\u7684\u4ee3\u7801\uff0c\u4fbf\u4e8e\u8bfb\u8005\u590d\u73b0\u7ed3\u679c\uff0c\u5e76\u8fdb\u884c\u6df1\u5165\u5b66\u4e60\u3002 \u6b64\u4e66\u662f\u6211\u548c\u80e1\u535a\u5f3a\u4e00\u8d77\u5199\u7684\uff0c\u4e3b\u8981\u5185\u5bb9\u662f\u6df1\u5ea6\u5b66\u4e60\u3001\u56fe\u50cf\u5904\u7406\u5165\u95e8\uff0c\u4ee5\u53ca\u51e0\u4e2a\u57fa\u4e8e Keras \u7684\u9879\u76ee\u3002\u5982\u679c\u4f60\u5173\u6ce8\u4e86\u6211\u7684 github\uff0c\u90a3\u4e48\u6b64\u4e66\u662f\u4e0d\u9700\u8981\u4e70\u7684\uff0c\u56e0\u4e3a\u9879\u76ee\u5728 github \u4e0a\u90fd\u6709\uff1a \u732b\u72d7\u5927\u6218\uff1a https://github.com/ypwhs/dogs_vs_cats \u9a8c\u8bc1\u7801\u8bc6\u522b\uff1a https://github.com/ypwhs/captcha_break \u767e\u5ea6\u4e91\u9b45\u65cf\u6df1\u5ea6\u5b66\u4e60\u5e94\u7528\u5927\u8d5b\uff1a https://github.com/ypwhs/baiduyun_deeplearning_competition \u6df1\u5ea6\u5b66\u4e60 APP\uff1a https://github.com/ypwhs/CAM","title":"\u6df1\u5ea6\u5b66\u4e60\u6280\u672f\u56fe\u50cf\u5904\u7406\u5165\u95e8"},{"location":"detection-models/","text":"\u68c0\u6d4b\u6a21\u578b \u6a21\u578b\u6982\u89c8 \u76ee\u6807\u68c0\u6d4b\u6a21\u578b \u4e0b\u9762\u51e0\u4e2a\u6a21\u578b\u662f\u6bd4\u8f83\u7ecf\u5178\u7684\u68c0\u6d4b\u6a21\u578b\uff1a \u30101\u3011SSD 2015\u2014\u2014\u7ecf\u5178\u7684 OneStage \u6a21\u578b \u30102\u3011Faster R-CNN 2015\u2014\u2014\u7ecf\u5178\u7684 TwoStage \u6a21\u578b \u30103\u3011YOLO v3 2018\u2014\u2014\u901f\u5ea6\u8f83\u5feb\u7684\u68c0\u6d4b\u6a21\u578b \u30104\u3011CenterNet 2019\u2014\u2014AnchorFree \u6a21\u578b \u30105\u3011DETR 2020\u2014\u2014\u4f7f\u7528 Transformer \u505a\u68c0\u6d4b\u4efb\u52a1\u7684\u6a21\u578b \u30106\u3011YOLO v5 2020\u2014\u2014\u901f\u5ea6\u8f83\u5feb\u7684\u68c0\u6d4b\u6a21\u578b \u5b83\u4eec\u5728 COCO2017 \u4e0a\u7684\u5206\u6570\u5982\u4e0b\uff1a \u5b9e\u4f8b\u5206\u5272\u6a21\u578b \u4e0b\u9762\u51e0\u4e2a\u6a21\u578b\u662f\u6bd4\u8f83\u7ecf\u5178\u7684\u5b9e\u4f8b\u5206\u5272\u6a21\u578b\uff1a \u30101\u3011Mask R-CNN 2017\u2014\u2014\u73b0\u4ee3\u5316\u7684\u5b9e\u4f8b\u5206\u5272\u6a21\u578b \u30102\u3011Cascade Mask R-CNN 2019\u2014\u2014\u7ea7\u8054\u7684 Mask R-CNN \u30103\u3011QueryInst 2021\u2014\u2014\u76ee\u524d\u6392\u884c\u699c\u7b2c 10 \u540d \u30104\u3011SwinV2 2021\u2014\u2014\u76ee\u524d\u6392\u884c\u699c\u7b2c 1 \u540d \u5b83\u4eec\u5728 COCO2017 \u4e0a\u7684\u5206\u6570\u5982\u4e0b\uff1a \u5177\u4f53\u6a21\u578b\u4ecb\u7ecd SSD 2015 SSD: Single Shot MultiBox Detector SSD \u662f OneStage \u7684\u6a21\u578b\uff0c\u56e0\u4e3a\u6ca1\u6709 RPN\u3001ROI \u7b49\u64cd\u4f5c\uff0c\u6240\u4ee5\u901f\u5ea6\u4f1a\u5feb\u5f88\u591a\uff0c\u4ee3\u4ef7\u5728\u4e8e\u7cbe\u5ea6\u6709\u6240\u964d\u4f4e\u3002 YOLO \u4e0e SSD \u7684\u7ed3\u6784\u4e5f\u662f\u7c7b\u4f3c\u7684\uff0c\u4e0d\u8fc7\u4e00\u4ee3\u7684 YOLO \u6ca1\u6709\u4f7f\u7528\u4e2d\u95f4\u5c42\u7684\u7279\u5f81\u3002 \u6a21\u578b\u7ed3\u6784\u5982\u4e0b\uff1a YOLOv5 2022 YOLOv5 YOLOv5\u4e2d\u6587\u89e3\u6790 YOLOv5 \u4ecd\u7136\u662f\u5c5e\u4e8e OneStage \u6a21\u578b\uff0c\u5bf9\u7ed3\u6784\u8fdb\u884c\u4e86\u8bb8\u591a\u4f18\u5316\uff0c\u964d\u4f4e\u4e86\u8ba1\u7b97\u91cf\u3002\u5404\u79cd\u6570\u636e\u589e\u5f3a\u65b9\u6cd5\u4e5f\u63d0\u9ad8\u4e86\u6a21\u578b\u7684\u7cbe\u5ea6\u3002 Faster R-CNN 2015 Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks Faster R-CNN \u662f\u6700\u7ecf\u5178\u7684 TwoStage \u6a21\u578b\u3002 \u4f7f\u7528 RPN \u63d0\u53d6\u51fa\u53ef\u80fd\u662f\u7269\u4f53\u7684\u533a\u57df\uff0c\u7136\u540e\u4f7f\u7528 ROI Pooling \u6293\u51fa\u5c40\u90e8\u7279\u5f81\uff0c \u518d\u4f7f\u7528\u5206\u7c7b\u548c\u56de\u5f52\u5c06\u7c7b\u522b\u548c\u6846\u7684\u4f4d\u7f6e\u8ba1\u7b97\u51fa\u6765\u3002 \u4e0b\u56fe\u5c31\u662f FPN \u7ed3\u6784\u7684\u793a\u610f\uff1a \u4e0b\u56fe\u662f\u68c0\u6d4b\u5934\u7684\u7ed3\u6784\uff1a DETR 2020 End-to-End Object Detection with Transformers DETR \u4ecd\u7136\u662f\u4f7f\u7528 CNN \u63d0\u53d6\u7279\u5f81\uff0c\u4e0d\u8fc7\u6ca1\u6709\u4f7f\u7528\u4f20\u7edf\u7684 RPN \u548c\u68c0\u6d4b Head\uff0c\u56e0\u6b64\u4e5f\u6ca1\u6709 Anchor\uff0c\u4f7f\u7528\u4e86 Transformer \u76f4\u63a5\u68c0\u6d4b\u7269\u4f53\u3002 DETR \u7ed3\u6784\uff1a Transformer \u7ed3\u6784\uff1a Multi-Head Attention \u7ed3\u6784\uff1a Attention \u7ed3\u6784\uff1a Mask R-CNN 2017 Mask R-CNN \u7ecf\u5178\u7684 TwoStage \u6a21\u578b\uff0c\u68c0\u6d4b\u90e8\u5206\u548c Faster R-CNN \u4e00\u6837\uff0c\u5148\u63d0\u53d6\u53ef\u80fd\u662f\u7269\u4f53\u7684\u90e8\u5206\uff0c\u7136\u540e\u518d\u63d0\u53d6\u8fd9\u90e8\u5206\u533a\u57df\u7684\u7279\u5f81\u8ba1\u7b97\u7c7b\u522b\u548c\u6846\uff0c\u4f46\u662f\u591a\u4e86\u4e00\u4e2a Mask \u5206\u652f\uff0c\u7528\u4e8e\u9010\u50cf\u7d20\u5206\u7c7b\uff0c\u8ba1\u7b97\u8be5\u7269\u4f53\u7684 Mask\u3002 Cascade Mask R-CNN 2019 Cascade R-CNN: High Quality Object Detection and Instance Segmentation \u5c06\u6a21\u578b\u7684\u7ed3\u679c\u518d\u8f93\u5165\u5230\u65b0\u7684\u6a21\u578b\u91cc\u505a\u7cbe\u8c03\uff0c\u53cd\u590d\u51e0\u6b21\uff0c\u8fd9\u6837\u53ef\u4ee5\u63d0\u5347\u6a21\u578b\u7684\u51c6\u786e\u7387\uff0c\u4f46\u662f\u4e5f\u4f1a\u589e\u52a0\u8ba1\u7b97\u91cf\u3002 \u6a21\u578b\u53ef\u89c6\u5316\u5bf9\u6bd4 \u4e3a\u4e86\u7efc\u5408\u8bc4\u4ef7\u5404\u4e2a\u6a21\u578b\u7684\u80fd\u529b\uff0c\u6211\u4eec\u4f7f\u7528\u5404\u4e2a\u6a21\u578b\u5bf9\u4e0b\u56fe\u8fdb\u884c\u4e86\u63a8\u65ad\u548c\u53ef\u89c6\u5316\uff1a \u6a21\u578b\u540d\u79f0 \u5e74\u4efd bbox mAP \u53ef\u89c6\u5316\u56fe SSD Lite MobileNetV2 2015 21.3 YOLOv3 2018 33.7 YOLOv5s 2022 37.4 YOLOv5x6 2022 55.0 Faster R-CNN R50 2015 40.3 Mask R-CNN R50 2017 40.9 Cascade Mask R-CNN R50 2019 44.3 DETR R50 2020 40.1 Mask2Former R50 2021 44.8 Swin R50 2021 46.0 QueryInst R50 2021 47.5 \u53ef\u4ee5\u770b\u5230\uff0c\u4e0d\u662f mAP \u5206\u6570\u66f4\u9ad8\u7684\u6a21\u578b\u5c31\u66f4\u51c6\uff0c\u76ee\u524d\u57fa\u4e8e Anchor \u7684\u6a21\u578b\u4f9d\u7136\u5177\u5907\u6781\u5927\u7684\u4f18\u52bf\u3002","title":"\u68c0\u6d4b\u6a21\u578b"},{"location":"detection-models/#_1","text":"","title":"\u68c0\u6d4b\u6a21\u578b"},{"location":"detection-models/#_2","text":"","title":"\u6a21\u578b\u6982\u89c8"},{"location":"detection-models/#_3","text":"\u4e0b\u9762\u51e0\u4e2a\u6a21\u578b\u662f\u6bd4\u8f83\u7ecf\u5178\u7684\u68c0\u6d4b\u6a21\u578b\uff1a \u30101\u3011SSD 2015\u2014\u2014\u7ecf\u5178\u7684 OneStage \u6a21\u578b \u30102\u3011Faster R-CNN 2015\u2014\u2014\u7ecf\u5178\u7684 TwoStage \u6a21\u578b \u30103\u3011YOLO v3 2018\u2014\u2014\u901f\u5ea6\u8f83\u5feb\u7684\u68c0\u6d4b\u6a21\u578b \u30104\u3011CenterNet 2019\u2014\u2014AnchorFree \u6a21\u578b \u30105\u3011DETR 2020\u2014\u2014\u4f7f\u7528 Transformer \u505a\u68c0\u6d4b\u4efb\u52a1\u7684\u6a21\u578b \u30106\u3011YOLO v5 2020\u2014\u2014\u901f\u5ea6\u8f83\u5feb\u7684\u68c0\u6d4b\u6a21\u578b \u5b83\u4eec\u5728 COCO2017 \u4e0a\u7684\u5206\u6570\u5982\u4e0b\uff1a","title":"\u76ee\u6807\u68c0\u6d4b\u6a21\u578b"},{"location":"detection-models/#_4","text":"\u4e0b\u9762\u51e0\u4e2a\u6a21\u578b\u662f\u6bd4\u8f83\u7ecf\u5178\u7684\u5b9e\u4f8b\u5206\u5272\u6a21\u578b\uff1a \u30101\u3011Mask R-CNN 2017\u2014\u2014\u73b0\u4ee3\u5316\u7684\u5b9e\u4f8b\u5206\u5272\u6a21\u578b \u30102\u3011Cascade Mask R-CNN 2019\u2014\u2014\u7ea7\u8054\u7684 Mask R-CNN \u30103\u3011QueryInst 2021\u2014\u2014\u76ee\u524d\u6392\u884c\u699c\u7b2c 10 \u540d \u30104\u3011SwinV2 2021\u2014\u2014\u76ee\u524d\u6392\u884c\u699c\u7b2c 1 \u540d \u5b83\u4eec\u5728 COCO2017 \u4e0a\u7684\u5206\u6570\u5982\u4e0b\uff1a","title":"\u5b9e\u4f8b\u5206\u5272\u6a21\u578b"},{"location":"detection-models/#_5","text":"","title":"\u5177\u4f53\u6a21\u578b\u4ecb\u7ecd"},{"location":"detection-models/#ssd-2015","text":"SSD: Single Shot MultiBox Detector SSD \u662f OneStage \u7684\u6a21\u578b\uff0c\u56e0\u4e3a\u6ca1\u6709 RPN\u3001ROI \u7b49\u64cd\u4f5c\uff0c\u6240\u4ee5\u901f\u5ea6\u4f1a\u5feb\u5f88\u591a\uff0c\u4ee3\u4ef7\u5728\u4e8e\u7cbe\u5ea6\u6709\u6240\u964d\u4f4e\u3002 YOLO \u4e0e SSD \u7684\u7ed3\u6784\u4e5f\u662f\u7c7b\u4f3c\u7684\uff0c\u4e0d\u8fc7\u4e00\u4ee3\u7684 YOLO \u6ca1\u6709\u4f7f\u7528\u4e2d\u95f4\u5c42\u7684\u7279\u5f81\u3002 \u6a21\u578b\u7ed3\u6784\u5982\u4e0b\uff1a","title":"SSD 2015"},{"location":"detection-models/#yolov5-2022","text":"YOLOv5 YOLOv5\u4e2d\u6587\u89e3\u6790 YOLOv5 \u4ecd\u7136\u662f\u5c5e\u4e8e OneStage \u6a21\u578b\uff0c\u5bf9\u7ed3\u6784\u8fdb\u884c\u4e86\u8bb8\u591a\u4f18\u5316\uff0c\u964d\u4f4e\u4e86\u8ba1\u7b97\u91cf\u3002\u5404\u79cd\u6570\u636e\u589e\u5f3a\u65b9\u6cd5\u4e5f\u63d0\u9ad8\u4e86\u6a21\u578b\u7684\u7cbe\u5ea6\u3002","title":"YOLOv5 2022"},{"location":"detection-models/#faster-r-cnn-2015","text":"Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks Faster R-CNN \u662f\u6700\u7ecf\u5178\u7684 TwoStage \u6a21\u578b\u3002 \u4f7f\u7528 RPN \u63d0\u53d6\u51fa\u53ef\u80fd\u662f\u7269\u4f53\u7684\u533a\u57df\uff0c\u7136\u540e\u4f7f\u7528 ROI Pooling \u6293\u51fa\u5c40\u90e8\u7279\u5f81\uff0c \u518d\u4f7f\u7528\u5206\u7c7b\u548c\u56de\u5f52\u5c06\u7c7b\u522b\u548c\u6846\u7684\u4f4d\u7f6e\u8ba1\u7b97\u51fa\u6765\u3002 \u4e0b\u56fe\u5c31\u662f FPN \u7ed3\u6784\u7684\u793a\u610f\uff1a \u4e0b\u56fe\u662f\u68c0\u6d4b\u5934\u7684\u7ed3\u6784\uff1a","title":"Faster R-CNN 2015"},{"location":"detection-models/#detr-2020","text":"End-to-End Object Detection with Transformers DETR \u4ecd\u7136\u662f\u4f7f\u7528 CNN \u63d0\u53d6\u7279\u5f81\uff0c\u4e0d\u8fc7\u6ca1\u6709\u4f7f\u7528\u4f20\u7edf\u7684 RPN \u548c\u68c0\u6d4b Head\uff0c\u56e0\u6b64\u4e5f\u6ca1\u6709 Anchor\uff0c\u4f7f\u7528\u4e86 Transformer \u76f4\u63a5\u68c0\u6d4b\u7269\u4f53\u3002 DETR \u7ed3\u6784\uff1a Transformer \u7ed3\u6784\uff1a Multi-Head Attention \u7ed3\u6784\uff1a Attention \u7ed3\u6784\uff1a","title":"DETR 2020"},{"location":"detection-models/#mask-r-cnn-2017","text":"Mask R-CNN \u7ecf\u5178\u7684 TwoStage \u6a21\u578b\uff0c\u68c0\u6d4b\u90e8\u5206\u548c Faster R-CNN \u4e00\u6837\uff0c\u5148\u63d0\u53d6\u53ef\u80fd\u662f\u7269\u4f53\u7684\u90e8\u5206\uff0c\u7136\u540e\u518d\u63d0\u53d6\u8fd9\u90e8\u5206\u533a\u57df\u7684\u7279\u5f81\u8ba1\u7b97\u7c7b\u522b\u548c\u6846\uff0c\u4f46\u662f\u591a\u4e86\u4e00\u4e2a Mask \u5206\u652f\uff0c\u7528\u4e8e\u9010\u50cf\u7d20\u5206\u7c7b\uff0c\u8ba1\u7b97\u8be5\u7269\u4f53\u7684 Mask\u3002","title":"Mask R-CNN 2017"},{"location":"detection-models/#cascade-mask-r-cnn-2019","text":"Cascade R-CNN: High Quality Object Detection and Instance Segmentation \u5c06\u6a21\u578b\u7684\u7ed3\u679c\u518d\u8f93\u5165\u5230\u65b0\u7684\u6a21\u578b\u91cc\u505a\u7cbe\u8c03\uff0c\u53cd\u590d\u51e0\u6b21\uff0c\u8fd9\u6837\u53ef\u4ee5\u63d0\u5347\u6a21\u578b\u7684\u51c6\u786e\u7387\uff0c\u4f46\u662f\u4e5f\u4f1a\u589e\u52a0\u8ba1\u7b97\u91cf\u3002","title":"Cascade Mask R-CNN 2019"},{"location":"detection-models/#_6","text":"\u4e3a\u4e86\u7efc\u5408\u8bc4\u4ef7\u5404\u4e2a\u6a21\u578b\u7684\u80fd\u529b\uff0c\u6211\u4eec\u4f7f\u7528\u5404\u4e2a\u6a21\u578b\u5bf9\u4e0b\u56fe\u8fdb\u884c\u4e86\u63a8\u65ad\u548c\u53ef\u89c6\u5316\uff1a \u6a21\u578b\u540d\u79f0 \u5e74\u4efd bbox mAP \u53ef\u89c6\u5316\u56fe SSD Lite MobileNetV2 2015 21.3 YOLOv3 2018 33.7 YOLOv5s 2022 37.4 YOLOv5x6 2022 55.0 Faster R-CNN R50 2015 40.3 Mask R-CNN R50 2017 40.9 Cascade Mask R-CNN R50 2019 44.3 DETR R50 2020 40.1 Mask2Former R50 2021 44.8 Swin R50 2021 46.0 QueryInst R50 2021 47.5 \u53ef\u4ee5\u770b\u5230\uff0c\u4e0d\u662f mAP \u5206\u6570\u66f4\u9ad8\u7684\u6a21\u578b\u5c31\u66f4\u51c6\uff0c\u76ee\u524d\u57fa\u4e8e Anchor \u7684\u6a21\u578b\u4f9d\u7136\u5177\u5907\u6781\u5927\u7684\u4f18\u52bf\u3002","title":"\u6a21\u578b\u53ef\u89c6\u5316\u5bf9\u6bd4"},{"location":"docker-is-good/","text":"Docker \u662f\u4e2a\u597d\u4e1c\u897f \u4ec0\u4e48\u662f Docker \u5b89\u88c5 Docker \u5b89\u88c5 nvidia-docker \u5982\u4f55\u7f16\u5199 Dockerfile \u5982\u4f55\u7f16\u8bd1\u4e00\u4e2a Docker \u955c\u50cf \u5982\u4f55\u8fd0\u884c Docker \u4ec0\u4e48\u662f Docker https://docs.docker.com/ Docker \u53ef\u4ee5\u8ba9\u4f60\u628a\u6574\u4e2a\u5e94\u7528\u6253\u5305\u6210\u4e00\u4e2a\u6587\u4ef6\uff0c\u5b83\u5305\u542b\u4f60\u5b89\u88c5\u7684\u5404\u79cd\u4f9d\u8d56\u73af\u5883\uff0c\u6bd4\u5982 CUDA\u3001cuDNN\u3001TensorFlow \u7b49\u3002\u5176\u4ed6\u4eba\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 Docker \u76f4\u63a5\u8fd0\u884c\u4f60\u6253\u5305\u7684\u8fd9\u4e2a\u955c\u50cf\uff0c\u4e0d\u9700\u8981\u8fdb\u884c\u7e41\u7410\u7684\u73af\u5883\u914d\u7f6e\u3002 Docker \u7684\u4f18\u70b9\uff1a \u7075\u6d3b\uff0c\u4e0d\u7ba1\u4f60\u7684\u5e94\u7528\u73af\u5883\u6709\u591a\u590d\u6742\uff0c\u90fd\u53ef\u4ee5\u6253\u5305\u6210\u4e00\u4e2a\u955c\u50cf \u4fbf\u643a\uff0c\u53ea\u9700\u8981\u6253\u5305\u4e00\u6b21\uff0c\u5c31\u53ef\u4ee5\u90e8\u7f72\u5230\u4efb\u4f55\u5730\u65b9\u8fd0\u884c \u9ad8\u6548\uff0c\u4e0e\u5bbf\u4e3b\u673a\u5171\u4eab\u64cd\u4f5c\u7cfb\u7edf\u5185\u6838\uff0c\u6548\u7387\u5f88\u9ad8 \u5b89\u5168\uff0c\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u4e92\u4e0d\u5e72\u6270\uff0c\u5d29\u4e86\u4e0d\u5f71\u54cd\u5176\u4ed6\u5e94\u7528 \u5728\u6ca1\u6709 Docker \u4e4b\u524d\uff0c\u8fd0\u7ef4\u9700\u8981\u5b66\u4f1a\u914d\u7f6e\u5404\u79cd\u73af\u5883\u3001\u9a71\u52a8\uff0c\u89e3\u51b3\u5404\u79cd\u5e93\u4e4b\u95f4\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u73b0\u5728\u53ea\u9700\u8981\u88c5\u597d\u5fc5\u8981\u7684\u9a71\u52a8\uff0c\u7136\u540e\u8fd0\u884c Docker \u5c31\u597d\uff0c\u975e\u5e38\u65b9\u4fbf\u3002 \u5b89\u88c5 Docker https://docs.docker.com/install/linux/docker-ce/ubuntu/ \u6309\u7167\u5b98\u7f51\u4e0a\u7684\u6559\u7a0b\u5b89\u88c5\u5373\u53ef\uff0c\u4e0b\u9762\u662f\u6211\u8fd0\u884c\u7684\u547d\u4ee4\uff1a curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh \u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u4f7f\u7528 docker \u547d\u4ee4\u90fd\u8981\u52a0 sudo\uff0c\u4f60\u53ef\u4ee5\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a sudo usermod -aG docker $USER \u6dfb\u52a0\u4ee5\u540e\uff0c\u4f60\u9700\u8981\u91cd\u65b0\u767b\u5f55\u673a\u5668\u624d\u80fd\u751f\u6548\u3002 \u4f60\u53ef\u4ee5\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6d4b\u8bd5 docker\uff1a docker run hello-world \u671f\u671b\u8f93\u51fa\uff1a Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the \"hello-world\" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/ \u5982\u679c\u51fa\u73b0\u4e86\u6743\u9650\u95ee\u9898\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u91cd\u65b0\u6784\u5efa docker \u7684\u6587\u4ef6\u7cfb\u7edf\uff1a sudo service docker stop sudo rm -rf /var/lib/docker sudo service docker start","title":"Docker \u662f\u4e2a\u597d\u4e1c\u897f"},{"location":"docker-is-good/#docker","text":"\u4ec0\u4e48\u662f Docker \u5b89\u88c5 Docker \u5b89\u88c5 nvidia-docker \u5982\u4f55\u7f16\u5199 Dockerfile \u5982\u4f55\u7f16\u8bd1\u4e00\u4e2a Docker \u955c\u50cf \u5982\u4f55\u8fd0\u884c Docker","title":"Docker \u662f\u4e2a\u597d\u4e1c\u897f"},{"location":"docker-is-good/#docker_1","text":"https://docs.docker.com/ Docker \u53ef\u4ee5\u8ba9\u4f60\u628a\u6574\u4e2a\u5e94\u7528\u6253\u5305\u6210\u4e00\u4e2a\u6587\u4ef6\uff0c\u5b83\u5305\u542b\u4f60\u5b89\u88c5\u7684\u5404\u79cd\u4f9d\u8d56\u73af\u5883\uff0c\u6bd4\u5982 CUDA\u3001cuDNN\u3001TensorFlow \u7b49\u3002\u5176\u4ed6\u4eba\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 Docker \u76f4\u63a5\u8fd0\u884c\u4f60\u6253\u5305\u7684\u8fd9\u4e2a\u955c\u50cf\uff0c\u4e0d\u9700\u8981\u8fdb\u884c\u7e41\u7410\u7684\u73af\u5883\u914d\u7f6e\u3002 Docker \u7684\u4f18\u70b9\uff1a \u7075\u6d3b\uff0c\u4e0d\u7ba1\u4f60\u7684\u5e94\u7528\u73af\u5883\u6709\u591a\u590d\u6742\uff0c\u90fd\u53ef\u4ee5\u6253\u5305\u6210\u4e00\u4e2a\u955c\u50cf \u4fbf\u643a\uff0c\u53ea\u9700\u8981\u6253\u5305\u4e00\u6b21\uff0c\u5c31\u53ef\u4ee5\u90e8\u7f72\u5230\u4efb\u4f55\u5730\u65b9\u8fd0\u884c \u9ad8\u6548\uff0c\u4e0e\u5bbf\u4e3b\u673a\u5171\u4eab\u64cd\u4f5c\u7cfb\u7edf\u5185\u6838\uff0c\u6548\u7387\u5f88\u9ad8 \u5b89\u5168\uff0c\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u4e92\u4e0d\u5e72\u6270\uff0c\u5d29\u4e86\u4e0d\u5f71\u54cd\u5176\u4ed6\u5e94\u7528 \u5728\u6ca1\u6709 Docker \u4e4b\u524d\uff0c\u8fd0\u7ef4\u9700\u8981\u5b66\u4f1a\u914d\u7f6e\u5404\u79cd\u73af\u5883\u3001\u9a71\u52a8\uff0c\u89e3\u51b3\u5404\u79cd\u5e93\u4e4b\u95f4\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u73b0\u5728\u53ea\u9700\u8981\u88c5\u597d\u5fc5\u8981\u7684\u9a71\u52a8\uff0c\u7136\u540e\u8fd0\u884c Docker \u5c31\u597d\uff0c\u975e\u5e38\u65b9\u4fbf\u3002","title":"\u4ec0\u4e48\u662f Docker"},{"location":"docker-is-good/#docker_2","text":"https://docs.docker.com/install/linux/docker-ce/ubuntu/ \u6309\u7167\u5b98\u7f51\u4e0a\u7684\u6559\u7a0b\u5b89\u88c5\u5373\u53ef\uff0c\u4e0b\u9762\u662f\u6211\u8fd0\u884c\u7684\u547d\u4ee4\uff1a curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh \u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u4f7f\u7528 docker \u547d\u4ee4\u90fd\u8981\u52a0 sudo\uff0c\u4f60\u53ef\u4ee5\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a sudo usermod -aG docker $USER \u6dfb\u52a0\u4ee5\u540e\uff0c\u4f60\u9700\u8981\u91cd\u65b0\u767b\u5f55\u673a\u5668\u624d\u80fd\u751f\u6548\u3002 \u4f60\u53ef\u4ee5\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6d4b\u8bd5 docker\uff1a docker run hello-world \u671f\u671b\u8f93\u51fa\uff1a Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the \"hello-world\" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/ \u5982\u679c\u51fa\u73b0\u4e86\u6743\u9650\u95ee\u9898\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u91cd\u65b0\u6784\u5efa docker \u7684\u6587\u4ef6\u7cfb\u7edf\uff1a sudo service docker stop sudo rm -rf /var/lib/docker sudo service docker start","title":"\u5b89\u88c5 Docker"},{"location":"how-to-build-deep-learning-workstation/","text":"\u5982\u4f55\u914d\u7f6e\u4e00\u53f0\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9? \u8fd9\u7bc7\u6587\u7ae0\u4e3b\u8981\u4ecb\u7ecd\u7684\u662f\u5bb6\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9\uff0c\u5178\u578b\u7684\u914d\u7f6e\u6709\u4e24\u79cd\uff0c\u5206\u522b\u662f\u4e00\u4e2a GPU \u7684\u673a\u5668\u548c \u56db\u4e2a GPU\u7684\u673a\u5668\u3002\u5982\u679c\u9700\u8981\u66f4\u591a\u7684 GPU \u53ef\u4ee5\u8003\u8651\u914d\u7f6e\u4e24\u53f0\u56db\u4e2a GPU \u7684\u673a\u5668\u3002\u5982\u679c\u5e0c\u671b\u4e00\u53f0\u673a\u5668\u540c\u65f6\u5177\u5907 8~10 \u4e2a GPU \u9700\u8981\u8054\u7cfb \u4e13\u95e8\u7684\u4f9b\u5e94\u5546 \u8fdb\u884c\u914d\u7f6e\uff0c\u5e76\u4e14\u9700\u8981\u4e13\u4e1a\u7684\u673a\u623f\u5b58\u653e\u8fd9\u4e9b\u670d\u52a1\u5668\uff0c\u653e\u5728\u5bb6\u91cc\u566a\u58f0\u5f88\u5927\u5e76\u4e14\u5bb9\u6613\u8df3\u95f8\u3002 CPU \u7531\u4e8e\u6700\u8fd1 AMD \u548c Intel \u9891\u7e41\u66f4\u65b0 CPU\uff0c\u56e0\u6b64\u5927\u5bb6\u9009\u62e9\u65b0\u6b3e\u7684 CPU \u6bd4\u8f83\u597d\u3002 CPU \u4e0e GPU \u7684\u5173\u7cfb CPU \u74f6\u9888\u6ca1\u6709\u90a3\u4e48\u5927\uff0c\u4e00\u822c\u4ee5\u4e00\u4e2a GPU \u5bf9\u5e94 2~4 \u4e2a CPU \u6838\u6bd4\u8f83\u597d\uff0c\u6bd4\u5982\u5355\u5361\u673a\u5668\u4e70\u56db\u6838 CPU\uff0c\u56db\u5361\u673a\u5668\u4e70\u5341\u6838 CPU\u3002 \u5f53\u4f60\u5728\u8bad\u7ec3\u7684\u65f6\u5019\uff0c\u53ea\u8981\u6570\u636e\u751f\u6210\u5668\uff08DataLoader\uff09\u7684\u4ea7\u51fa\u901f\u5ea6\u6bd4 GPU \u7684\u6d88\u8017\u901f\u5ea6\u5feb\uff0c\u90a3\u4e48 CPU \u5c31\u4e0d\u4f1a\u6210\u4e3a\u74f6\u9888\uff0c\u4e5f\u5c31\u4e0d\u4f1a\u62d6\u6162\u8bad\u7ec3\u901f\u5ea6\u3002 PCI-E \u652f\u6301\u60c5\u51b5 \u9664\u4e86\u6838\u6570\uff0c\u4f60\u8fd8\u9700\u8981\u6ce8\u610f PCI-E \u652f\u6301\u60c5\u51b5\uff0c\u4e00\u822c\u663e\u5361\u662f PCI-E 4.0 x16\uff0c\u6bd4\u5982 i9-10900X \u7684 PCI-E \u901a\u9053\u6570\u662f 48 \uff0c\u914d\u7f6e\u56db\u5361\u7684\u8bdd\uff0c\u53ea\u80fd\u652f\u6301 1x16+3x8\uff0c\u4e5f\u5c31\u662f\u5355\u5361\u5168\u901f\uff0c\u4e09\u5361\u534a\u901f\u3002\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u8003\u8651\u9009\u62e9\u5e26\u6709 PLX \u6865\u63a5\u82af\u7247\u7684\u4e3b\u677f\uff0c\u6bd4\u5982 Pro WS X299 SAGE II \u3002 \u82f1\u7279\u5c14CPU \u82f1\u7279\u5c14 CPU \u5929\u68af\u56fe\u5982\u4e0b\uff1a \u5982\u679c\u672c\u6587\u5df2\u7ecf\u8fc7\u65f6\uff0c\u4f60\u53ef\u4ee5\u641c\u7d22\u5173\u952e\u5b57\u3010CPU \u5929\u68af\u56fe\u3011\u67e5\u627e\u6700\u65b0\u7684 CPU \u4fe1\u606f\u3002 \u5355\u5361\u6839\u636e\u9884\u7b97\u9009\u62e9\u5408\u9002\u7684 CPU\uff0c\u53cc\u5361\u673a\u5668\u5efa\u8bae\u9009 i9-10900 \u7cfb\u5217\uff0c\u56db\u5361\u673a\u5668\u6309\u7167\u9884\u7b97\u9009 X\u7cfb\u5217 \u7684 CPU\u3002\uff08\u6ce8\u610f\uff0cX \u7cfb\u5217\u6700\u65b0\u53d1\u5e03\u7684 CPU \u662f 2019 \u5e74\u7684\uff0c\u5df2\u7ecf\u4e0d\u5efa\u8bae\u4f7f\u7528\uff09 \u4e3b\u677f \u4e3b\u677f\u9700\u8981\u6ce8\u610f\uff1a CPU \u63a5\u53e3\u662f\u5426\u80fd\u5bf9\u4e0a\uff0c\u5982 LGA1700 \u4e0e LGA206 PCI-E \u63d2\u69fd\u7684\u9ad8\u5ea6\u662f\u5426\u591f\u63d2\u663e\u5361\uff0c\u6bd4\u5982 PCI-E \u63d2\u53e3\u4e4b\u95f4\u7684\u8ddd\u79bb\u81f3\u5c11\u8981\u6ee1\u8db3 \u53cc\u69fd\u5bbd\u663e\u5361\u7684\u9ad8\u5ea6 PCI-E \u540c\u65f6\u53ef\u4ee5\u652f\u6301\u51e0\u5f20\u5361\u4ee5\u4ec0\u4e48\u6837\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5982 1x16 + 3x8 \u662f\u5e38\u89c1\u7684\u914d\u7f6e \u4e3b\u677f\u5fc5\u770b\u53c2\u6570 GIGABYTE X299 AORUS MASTER (rev. 1.0) \u4f7f\u7528\u4e86 4 \u7ec4 2 \u69fd\u95f4\u8ddd\u663e\u5361\u63d2\u69fd\u8bbe\u8ba1\uff0c\u652f\u6301 1x16\u30012x16\u30012x16 + 1x8\u30011x16 + 3x8 \u56db\u79cd\u914d\u7f6e\uff08\u9700\u8981\u5341\u6838\u4ee5\u4e0a\u7684 CPU\uff09\uff0c\u8fd9\u91cc\u8bf7\u53c2\u9605\u8bf4\u660e\u4e66\u5b89\u88c5\u663e\u5361\uff0c\u5b89\u88c5\u5728\u4e0d\u540c\u4f4d\u7f6e\u7684\u901f\u5ea6\u662f\u4e0d\u4e00\u6837\u7684\uff1a \u5e26\u6709\u6865\u63a5\u82af\u7247\u7684\u4e3b\u677f \u6709\u7684\u4e3b\u677f\u5982 Pro WS X299 SAGE II \u5e26\u6709 PLX \u6865\u63a5\u82af\u7247\uff0c\u53ef\u4ee5\u5728 CPU \u6ca1\u6709\u8db3\u591f PCI-E \u7684\u60c5\u51b5\u4e0b\u8fbe\u5230\u56db\u5361 x16 \u7684\u901f\u5ea6\uff1a \u5728\u591a\u5361\u5e76\u884c\u8bad\u7ec3\u7684\u65f6\u5019\uff0cPCI-E \u7684\u4f20\u8f93\u901f\u5ea6\u51b3\u5b9a\u4e86\u68af\u5ea6\u540c\u6b65\u7684\u901f\u5ea6\uff0c\u5982\u679c\u4f60\u8bad\u7ec3\u7684\u7684\u6a21\u578b\u6bd4\u8f83\u5927\uff0c\u5e0c\u671b\u642d\u5efa\u591a\u5361\u673a\u5668\uff0c\u5efa\u8bae\u9009\u62e9\u652f\u6301\u56db\u8def PCI-E x16 \u7684\u4e3b\u677f\u3002 \u663e\u5361 \u663e\u5361\u6027\u80fd\u8868 \u578b\u53f7 \u4ef7\u683c\uff08\u5143\uff09 \u663e\u5b58\uff08GB\uff09 \u6027\u80fd \uff08TFLOPS\uff09 \u539a\u5ea6\uff08\u69fd\u5bbd\uff09 3090 12,799 24 328 3 3080Ti 8,999 12 320 3 3080 6,499 10 280 3 3070Ti 5,199 16 184 3 3070 4,599 8 162 3 3060 3,599 12 112 3 3050 2,499 8 80 3 3090\u6da1\u8f6e 15,399 24 328 2 3080Ti\u6da1\u8f6e 10,399 12 320 2 3080\u6da1\u8f6e 7,899 10 280 2 3070Ti\u6da1\u8f6e 6,799 16 184 2 3060\u6da1\u8f6e 3,899 12 112 2 A2000 3,300 12 64 1 A4000 6,000 16 153 1 A4500 11,000 20 189 2 A5000 14,500 24 222 2 A6000 26,800 48 310 2 T4 10,500 16 65 1 \u8bad\u7ec3\u9700\u8981 FP32 \u548c FP16 \u7684\u6027\u80fd\uff0c\u63a8\u65ad\u9700\u8981 INT8 \u7684\u6027\u80fd\u3002\u8bad\u7ec3\u5927\u6a21\u578b\u9700\u8981\u6ce8\u610f\u663e\u5b58\u5927\u5c0f\u3002 \u8003\u8651\u6027\u4ef7\u6bd4\u53ef\u4ee5\u4e70 RTX 3080Ti\uff0c\u60f3\u8981\u5927\u663e\u5b58\u6bd4\u53ef\u4ee5\u4e70 RTX 3090\u3002 \u503c\u5f97\u6ce8\u610f\u7684\u662f\uff0c\u5b98\u65b9\u516c\u5e03\u7684\u53c2\u6570\u5e76\u4e0d\u4e00\u5b9a\u662f\u6700\u7ec8\u6027\u80fd\uff0c\u5b9e\u6d4b A6000 \u662f\u6bd4 3090 \u5feb\u7684\uff1a \u53c2\u8003\u94fe\u63a5\uff1a Ampere \u67b6\u6784\u767d\u76ae\u4e66 Best GPU for Deep Learning in 2022 (so far) \u6da1\u8f6e\u4e0e\u98ce\u6247 \u91c7\u8d2d\u663e\u5361\u7684\u65f6\u5019\uff0c\u4e00\u5b9a\u8981\u6ce8\u610f\u4e70\u6da1\u8f6e\u7248\u7684\uff0c\u4e0d\u8981\u4e70\u4e24\u4e2a\u6216\u8005\u4e09\u4e2a\u98ce\u6247\u7684\u7248\u672c\uff0c\u9664\u975e\u4f60\u53ea\u6253\u7b97\u4e70\u4e00\u5f20\u5361\u3002 \u56e0\u4e3a\u6da1\u8f6e\u98ce\u6247\u7684\u70ed\u662f\u5f80\u5916\u673a\u7bb1\u5916\u90e8\u5439\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5f88\u597d\u5730\u5e26\u8d70\u70ed\u91cf\uff0c\u6563\u70ed\u6bd4\u8f83\u597d\u3002\u5982\u679c\u4e70\u4e09\u4e2a\u98ce\u6247\u7684\u7248\u672c\uff0c\u63d2\u591a\u5361\u7684\u65f6\u5019\uff0c\u4e0a\u9762\u7684\u5361\u4f1a\u628a\u70ed\u91cf\u5439\u5411\u7b2c\u4e8c\u5f20\u5361\uff0c\u5bfc\u81f4\u7b2c\u4e8c\u5f20\u5361\u6e29\u5ea6\u8fc7\u9ad8\uff0c\u5f71\u54cd\u6027\u80fd\u3002 \u98ce\u6247\u663e\u5361\u5f88\u6709\u53ef\u80fd\u662f\u8d85\u8fc7\u53cc\u69fd\u5bbd\u7684\uff0c\u7b2c\u4e8c\u5f20\u5361\u53ef\u80fd\u63d2\u4e0d\u4e0a\u7b2c\u4e8c\u4e2a PCI-E \u63d2\u69fd\uff0c\u8fd9\u4e2a\u4e5f\u9700\u8981\u6ce8\u610f\u3002 \u6da1\u8f6e\uff1a \u7d22\u6cf0 GeForce\u00ae RTX2080-8GD6 AI\u7248 OC HA \u98ce\u6247\uff1a \u534e\u7855 ROG \u731b\u79bd\u7cfb\u5217 GeForce RTX\u2122 2080 Ti OC\u7248 \u786c\u76d8 \u786c\u76d8\u7c7b\u578b \u5e38\u7528\u786c\u76d8\u63a5\u53e3\u6709\u4e09\u79cd\uff1a SATA3.0\uff0c\u901f\u5ea6 600MB/s SAS\uff0c\u901f\u5ea6 1200MB/s PCIE 3.0 x4\uff08NVMe\uff09\uff0c\u901f\u5ea6 3.93GB/s PCIE 4.0 x4\uff08NVMe\uff09\uff0c\u901f\u5ea6 7.87GB/s \u53c2\u6570\u5bf9\u6bd4 \u4e0b\u9762\u662f\u6839\u636e\u4ee3\u8868\u4ea7\u54c1\u67e5\u8be2\u7684\u53c2\u6570\uff1a \u7c7b\u578b \u4ef7\u683c(\u5143/TB) \u8bfb\u53d6\u901f\u5ea6(MB/s) \u5199\u5165\u901f\u5ea6 4K\u968f\u673a\u8bfb\u53d6(IOPS) 4K\u968f\u673a\u5199\u5165(IOPS) SATA3 \u673a\u68b0\u786c\u76d8 150 270 258 170 550 SATA3 \u56fa\u6001\u786c\u76d8 700 560 530 98000 88000 NVMe \u56fa\u6001\u786c\u76d8 800 3500 3000 500000 480000 \u6ce8\uff1a SATA3 \u673a\u68b0\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a Seagate Exos X18 ST18000NM000J SATA3 \u56fa\u6001\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a 870 QVO SATA 2.5\u82f1\u5bf8 \u56fa\u6001\u786c\u76d8 NVMe \u56fa\u6001\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a 980 NVMe\u2122 M.2 \u56fa\u6001\u786c\u76d8 \u5728\u9762\u5bf9\u5927\u91cf\u5c0f\u6587\u4ef6\u7684\u65f6\u5019\uff0c\u4f7f\u7528 NVMe \u786c\u76d8\u53ef\u4ee5\u4e00\u5206\u949f\u626b\u5b8c 1000\u4e07\u6587\u4ef6\uff0c\u5982\u679c\u4f7f\u7528\u666e\u901a\u786c\u76d8\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u4e00\u5929\u65f6\u95f4\u3002\u4e3a\u4e86\u8282\u7701\u751f\u547d\uff0c\u7b80\u5316\u4ee3\u7801\uff0c\u786c\u76d8\u5efa\u8bae\u9009\u62e9 NVMe \u534f\u8bae\u7684\u56fa\u6001\u786c\u76d8\u3002 \u5982\u679c\u4f60\u7684\u4e3b\u677f\u4e0d\u591f\u65b0\uff0c\u6ca1\u6709 NVMe \u63d2\u69fd\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 M.2 \u8f6c\u63a5\u5361\u5c06 M.2 \u63a5\u53e3\u8f6c\u4e3a PCI-E \u63a5\u53e3\u3002 \u5185\u5b58 \u5185\u5b58\u5bb9\u91cf\u7684\u9009\u62e9\u901a\u5e38\u5927\u4e8e\u663e\u5b58\uff0c\u6bd4\u5982\u5355\u5361\u914d 16GB \u5185\u5b58\uff0c\u56db\u5361\u914d 64GB \u5185\u5b58\u3002\u7531\u4e8e\u6709\u6570\u636e\u751f\u6210\u5668\uff08DataLoader\uff09\uff0c\u6570\u636e\u4e0d\u5fc5\u5168\u90e8\u52a0\u8f7d\u5230\u5185\u5b58\u91cc\uff0c\u901a\u5e38\u4e0d\u4f1a\u6210\u4e3a\u74f6\u9888\u3002 \u7535\u6e90 \u5148\u8ba1\u7b97\u529f\u7387\u603b\u548c\uff0c\u5982\u5355\u5361 CPU 250W\uff0c\u663e\u5361 350W\uff0c\u52a0\u4e0a\u5176\u4ed6\u7684\u5927\u6982 200W\uff0c\u90a3\u4e48\u5c31\u4e70 850W \u7684\u7535\u6e90\u3002 \u53cc\u5361\u6700\u597d\u4e70 1200W \u4ee5\u4e0a\u7684\u7535\u6e90\uff0c\u56db\u5361\u6700\u597d\u4e70 2000W \u7684\u7535\u6e90\u3002\u5982\u679c\u7535\u6e90\u4e0d\u591f\uff0c\u8dd1\u8d77\u6765\u6240\u6709\u7684\u5361\u4ee5\u540e\u4f1a\u56e0\u4e3a\u7535\u6e90\u4e0d\u8db3\u800c\u81ea\u52a8\u5173\u673a\u3002 \u4e00\u822c\u5899\u4e0a\u7684\u63d2\u5ea7\u53ea\u652f\u6301 220V 10A\uff0c\u4e5f\u5c31\u662f 2200W \u7684\u4ea4\u6d41\u7535\uff0c\u7531\u4e8e\u7535\u6e90\u8981\u628a\u4ea4\u6d41\u7535\u8f6c\u76f4\u6d41\u7535\uff0c\u6240\u4ee5\u4f1a\u6709\u4e00\u4e9b\u635f\u8017\uff0c\u6700\u9ad8\u53ea\u6709 2000W\uff0c\u56e0\u6b64\u5982\u679c\u60f3\u8981\u652f\u6301\u516b\u5361\uff0c\u6700\u597d\u4e0d\u8981\u5728\u5bb6\u5c1d\u8bd5\u3002\u516b\u5361\u4e00\u822c\u662f\u56db\u4e2a PDU \u7535\u6e90\uff0c\u5e76\u4e14\u7535\u6d41\u5f88\u5927\uff0c\u6240\u4ee5\u9700\u8981\u4e13\u95e8\u8d70\u7ebf\uff0c\u5982\u679c\u5728\u5bb6\u76f4\u63a5\u4ece\u5899\u4e0a\u63a5\u63d2\u5ea7\uff0c\u7136\u540e\u63d2\u56db\u4e2a\u7535\u6e90\uff0c\u5bb9\u6613\u5f15\u53d1\u706b\u707e\u3002 \u7f51\u5361 \u4e00\u822c\u4e3b\u677f\u81ea\u5e26\u5343\u5146\u7f51\u5361\u3002\u5982\u679c\u9700\u8981\u7ec4\u5efa\u591a\u673a\u591a\u5361\u96c6\u7fa4\uff0c\u8bf7\u8054\u7cfb\u4f9b\u5e94\u5546\u54a8\u8be2\u4e13\u4e1a\u7684\u89e3\u51b3\u65b9\u6848\u3002 \u673a\u7bb1 \u5982\u679c\u914d\u5355\u5361\uff0c\u53ef\u4ee5\u76f4\u63a5\u4e70\u4e2a\u666e\u901a\u4e2d\u5854\u673a\u7bb1\uff0c\u6ce8\u610f\u663e\u5361\u957f\u5ea6\u80fd\u653e\u4e0b\u5c31\u884c\u3002 \u5982\u679c\u914d\u56db\u5361\u673a\u5668\uff0c\u5efa\u8bae\u4e70\u4e00\u4e2a\u5168\u5854\u673a\u7bb1\u3002 \u4e0b\u56fe\u662f\u6211\u642d\u5efa\u56db\u5361\u65f6\u4f7f\u7528\u7684\u673a\u7bb1\uff0c\u73b0\u5728\u5df2\u7ecf\u505c\u4ea7\u4e86\u3002 \u663e\u793a\u5668\u4e0e\u952e\u76d8\u9f20\u6807 \u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9\u88c5\u597d\u7cfb\u7edf\u4ee5\u540e\u5c31\u4e0d\u9700\u8981\u663e\u793a\u5668\u548c\u952e\u9f20\u5957\u88c5\u4e86\uff0c\u88c5\u7cfb\u7edf\u7684\u65f6\u5019\u4f7f\u7528\u624b\u8fb9\u7684\u663e\u793a\u5668\u548c\u952e\u76d8\u9f20\u6807\u5c31\u884c\u3002 \u6211\u4eec\u4e00\u822c\u4f1a\u5728\u6df1\u5ea6\u5b66\u4e60\u673a\u5668\u4e0a\u5b89\u88c5 Linux \u7cfb\u7edf\uff0c\u7136\u540e\u901a\u8fc7 Mac \u8fdc\u7a0b\u8fde\u63a5\uff0c\u901a\u8fc7 PyCharm \u8fdc\u7a0b\u8c03\u8bd5\uff0c\u6240\u4ee5\u4e3b\u673a\u53ea\u9700\u8981\u63d2\u7535\u548c\u63d2\u7f51\u7ebf\u5373\u53ef\uff0c\u4e0d\u9700\u8981\u8fde\u63a5\u663e\u793a\u5668\u548c\u952e\u76d8\u9f20\u6807\u3002","title":"\u5982\u4f55\u914d\u7f6e\u4e00\u53f0\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9?"},{"location":"how-to-build-deep-learning-workstation/#_1","text":"\u8fd9\u7bc7\u6587\u7ae0\u4e3b\u8981\u4ecb\u7ecd\u7684\u662f\u5bb6\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9\uff0c\u5178\u578b\u7684\u914d\u7f6e\u6709\u4e24\u79cd\uff0c\u5206\u522b\u662f\u4e00\u4e2a GPU \u7684\u673a\u5668\u548c \u56db\u4e2a GPU\u7684\u673a\u5668\u3002\u5982\u679c\u9700\u8981\u66f4\u591a\u7684 GPU \u53ef\u4ee5\u8003\u8651\u914d\u7f6e\u4e24\u53f0\u56db\u4e2a GPU \u7684\u673a\u5668\u3002\u5982\u679c\u5e0c\u671b\u4e00\u53f0\u673a\u5668\u540c\u65f6\u5177\u5907 8~10 \u4e2a GPU \u9700\u8981\u8054\u7cfb \u4e13\u95e8\u7684\u4f9b\u5e94\u5546 \u8fdb\u884c\u914d\u7f6e\uff0c\u5e76\u4e14\u9700\u8981\u4e13\u4e1a\u7684\u673a\u623f\u5b58\u653e\u8fd9\u4e9b\u670d\u52a1\u5668\uff0c\u653e\u5728\u5bb6\u91cc\u566a\u58f0\u5f88\u5927\u5e76\u4e14\u5bb9\u6613\u8df3\u95f8\u3002","title":"\u5982\u4f55\u914d\u7f6e\u4e00\u53f0\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9?"},{"location":"how-to-build-deep-learning-workstation/#cpu","text":"\u7531\u4e8e\u6700\u8fd1 AMD \u548c Intel \u9891\u7e41\u66f4\u65b0 CPU\uff0c\u56e0\u6b64\u5927\u5bb6\u9009\u62e9\u65b0\u6b3e\u7684 CPU \u6bd4\u8f83\u597d\u3002","title":"CPU"},{"location":"how-to-build-deep-learning-workstation/#cpu-gpu","text":"CPU \u74f6\u9888\u6ca1\u6709\u90a3\u4e48\u5927\uff0c\u4e00\u822c\u4ee5\u4e00\u4e2a GPU \u5bf9\u5e94 2~4 \u4e2a CPU \u6838\u6bd4\u8f83\u597d\uff0c\u6bd4\u5982\u5355\u5361\u673a\u5668\u4e70\u56db\u6838 CPU\uff0c\u56db\u5361\u673a\u5668\u4e70\u5341\u6838 CPU\u3002 \u5f53\u4f60\u5728\u8bad\u7ec3\u7684\u65f6\u5019\uff0c\u53ea\u8981\u6570\u636e\u751f\u6210\u5668\uff08DataLoader\uff09\u7684\u4ea7\u51fa\u901f\u5ea6\u6bd4 GPU \u7684\u6d88\u8017\u901f\u5ea6\u5feb\uff0c\u90a3\u4e48 CPU \u5c31\u4e0d\u4f1a\u6210\u4e3a\u74f6\u9888\uff0c\u4e5f\u5c31\u4e0d\u4f1a\u62d6\u6162\u8bad\u7ec3\u901f\u5ea6\u3002","title":"CPU \u4e0e GPU \u7684\u5173\u7cfb"},{"location":"how-to-build-deep-learning-workstation/#pci-e","text":"\u9664\u4e86\u6838\u6570\uff0c\u4f60\u8fd8\u9700\u8981\u6ce8\u610f PCI-E \u652f\u6301\u60c5\u51b5\uff0c\u4e00\u822c\u663e\u5361\u662f PCI-E 4.0 x16\uff0c\u6bd4\u5982 i9-10900X \u7684 PCI-E \u901a\u9053\u6570\u662f 48 \uff0c\u914d\u7f6e\u56db\u5361\u7684\u8bdd\uff0c\u53ea\u80fd\u652f\u6301 1x16+3x8\uff0c\u4e5f\u5c31\u662f\u5355\u5361\u5168\u901f\uff0c\u4e09\u5361\u534a\u901f\u3002\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u8003\u8651\u9009\u62e9\u5e26\u6709 PLX \u6865\u63a5\u82af\u7247\u7684\u4e3b\u677f\uff0c\u6bd4\u5982 Pro WS X299 SAGE II \u3002","title":"PCI-E \u652f\u6301\u60c5\u51b5"},{"location":"how-to-build-deep-learning-workstation/#cpu_1","text":"\u82f1\u7279\u5c14 CPU \u5929\u68af\u56fe\u5982\u4e0b\uff1a \u5982\u679c\u672c\u6587\u5df2\u7ecf\u8fc7\u65f6\uff0c\u4f60\u53ef\u4ee5\u641c\u7d22\u5173\u952e\u5b57\u3010CPU \u5929\u68af\u56fe\u3011\u67e5\u627e\u6700\u65b0\u7684 CPU \u4fe1\u606f\u3002 \u5355\u5361\u6839\u636e\u9884\u7b97\u9009\u62e9\u5408\u9002\u7684 CPU\uff0c\u53cc\u5361\u673a\u5668\u5efa\u8bae\u9009 i9-10900 \u7cfb\u5217\uff0c\u56db\u5361\u673a\u5668\u6309\u7167\u9884\u7b97\u9009 X\u7cfb\u5217 \u7684 CPU\u3002\uff08\u6ce8\u610f\uff0cX \u7cfb\u5217\u6700\u65b0\u53d1\u5e03\u7684 CPU \u662f 2019 \u5e74\u7684\uff0c\u5df2\u7ecf\u4e0d\u5efa\u8bae\u4f7f\u7528\uff09","title":"\u82f1\u7279\u5c14CPU"},{"location":"how-to-build-deep-learning-workstation/#_2","text":"\u4e3b\u677f\u9700\u8981\u6ce8\u610f\uff1a CPU \u63a5\u53e3\u662f\u5426\u80fd\u5bf9\u4e0a\uff0c\u5982 LGA1700 \u4e0e LGA206 PCI-E \u63d2\u69fd\u7684\u9ad8\u5ea6\u662f\u5426\u591f\u63d2\u663e\u5361\uff0c\u6bd4\u5982 PCI-E \u63d2\u53e3\u4e4b\u95f4\u7684\u8ddd\u79bb\u81f3\u5c11\u8981\u6ee1\u8db3 \u53cc\u69fd\u5bbd\u663e\u5361\u7684\u9ad8\u5ea6 PCI-E \u540c\u65f6\u53ef\u4ee5\u652f\u6301\u51e0\u5f20\u5361\u4ee5\u4ec0\u4e48\u6837\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5982 1x16 + 3x8 \u662f\u5e38\u89c1\u7684\u914d\u7f6e","title":"\u4e3b\u677f"},{"location":"how-to-build-deep-learning-workstation/#_3","text":"GIGABYTE X299 AORUS MASTER (rev. 1.0) \u4f7f\u7528\u4e86 4 \u7ec4 2 \u69fd\u95f4\u8ddd\u663e\u5361\u63d2\u69fd\u8bbe\u8ba1\uff0c\u652f\u6301 1x16\u30012x16\u30012x16 + 1x8\u30011x16 + 3x8 \u56db\u79cd\u914d\u7f6e\uff08\u9700\u8981\u5341\u6838\u4ee5\u4e0a\u7684 CPU\uff09\uff0c\u8fd9\u91cc\u8bf7\u53c2\u9605\u8bf4\u660e\u4e66\u5b89\u88c5\u663e\u5361\uff0c\u5b89\u88c5\u5728\u4e0d\u540c\u4f4d\u7f6e\u7684\u901f\u5ea6\u662f\u4e0d\u4e00\u6837\u7684\uff1a","title":"\u4e3b\u677f\u5fc5\u770b\u53c2\u6570"},{"location":"how-to-build-deep-learning-workstation/#_4","text":"\u6709\u7684\u4e3b\u677f\u5982 Pro WS X299 SAGE II \u5e26\u6709 PLX \u6865\u63a5\u82af\u7247\uff0c\u53ef\u4ee5\u5728 CPU \u6ca1\u6709\u8db3\u591f PCI-E \u7684\u60c5\u51b5\u4e0b\u8fbe\u5230\u56db\u5361 x16 \u7684\u901f\u5ea6\uff1a \u5728\u591a\u5361\u5e76\u884c\u8bad\u7ec3\u7684\u65f6\u5019\uff0cPCI-E \u7684\u4f20\u8f93\u901f\u5ea6\u51b3\u5b9a\u4e86\u68af\u5ea6\u540c\u6b65\u7684\u901f\u5ea6\uff0c\u5982\u679c\u4f60\u8bad\u7ec3\u7684\u7684\u6a21\u578b\u6bd4\u8f83\u5927\uff0c\u5e0c\u671b\u642d\u5efa\u591a\u5361\u673a\u5668\uff0c\u5efa\u8bae\u9009\u62e9\u652f\u6301\u56db\u8def PCI-E x16 \u7684\u4e3b\u677f\u3002","title":"\u5e26\u6709\u6865\u63a5\u82af\u7247\u7684\u4e3b\u677f"},{"location":"how-to-build-deep-learning-workstation/#_5","text":"","title":"\u663e\u5361"},{"location":"how-to-build-deep-learning-workstation/#_6","text":"\u578b\u53f7 \u4ef7\u683c\uff08\u5143\uff09 \u663e\u5b58\uff08GB\uff09 \u6027\u80fd \uff08TFLOPS\uff09 \u539a\u5ea6\uff08\u69fd\u5bbd\uff09 3090 12,799 24 328 3 3080Ti 8,999 12 320 3 3080 6,499 10 280 3 3070Ti 5,199 16 184 3 3070 4,599 8 162 3 3060 3,599 12 112 3 3050 2,499 8 80 3 3090\u6da1\u8f6e 15,399 24 328 2 3080Ti\u6da1\u8f6e 10,399 12 320 2 3080\u6da1\u8f6e 7,899 10 280 2 3070Ti\u6da1\u8f6e 6,799 16 184 2 3060\u6da1\u8f6e 3,899 12 112 2 A2000 3,300 12 64 1 A4000 6,000 16 153 1 A4500 11,000 20 189 2 A5000 14,500 24 222 2 A6000 26,800 48 310 2 T4 10,500 16 65 1 \u8bad\u7ec3\u9700\u8981 FP32 \u548c FP16 \u7684\u6027\u80fd\uff0c\u63a8\u65ad\u9700\u8981 INT8 \u7684\u6027\u80fd\u3002\u8bad\u7ec3\u5927\u6a21\u578b\u9700\u8981\u6ce8\u610f\u663e\u5b58\u5927\u5c0f\u3002 \u8003\u8651\u6027\u4ef7\u6bd4\u53ef\u4ee5\u4e70 RTX 3080Ti\uff0c\u60f3\u8981\u5927\u663e\u5b58\u6bd4\u53ef\u4ee5\u4e70 RTX 3090\u3002 \u503c\u5f97\u6ce8\u610f\u7684\u662f\uff0c\u5b98\u65b9\u516c\u5e03\u7684\u53c2\u6570\u5e76\u4e0d\u4e00\u5b9a\u662f\u6700\u7ec8\u6027\u80fd\uff0c\u5b9e\u6d4b A6000 \u662f\u6bd4 3090 \u5feb\u7684\uff1a \u53c2\u8003\u94fe\u63a5\uff1a Ampere \u67b6\u6784\u767d\u76ae\u4e66 Best GPU for Deep Learning in 2022 (so far)","title":"\u663e\u5361\u6027\u80fd\u8868"},{"location":"how-to-build-deep-learning-workstation/#_7","text":"\u91c7\u8d2d\u663e\u5361\u7684\u65f6\u5019\uff0c\u4e00\u5b9a\u8981\u6ce8\u610f\u4e70\u6da1\u8f6e\u7248\u7684\uff0c\u4e0d\u8981\u4e70\u4e24\u4e2a\u6216\u8005\u4e09\u4e2a\u98ce\u6247\u7684\u7248\u672c\uff0c\u9664\u975e\u4f60\u53ea\u6253\u7b97\u4e70\u4e00\u5f20\u5361\u3002 \u56e0\u4e3a\u6da1\u8f6e\u98ce\u6247\u7684\u70ed\u662f\u5f80\u5916\u673a\u7bb1\u5916\u90e8\u5439\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5f88\u597d\u5730\u5e26\u8d70\u70ed\u91cf\uff0c\u6563\u70ed\u6bd4\u8f83\u597d\u3002\u5982\u679c\u4e70\u4e09\u4e2a\u98ce\u6247\u7684\u7248\u672c\uff0c\u63d2\u591a\u5361\u7684\u65f6\u5019\uff0c\u4e0a\u9762\u7684\u5361\u4f1a\u628a\u70ed\u91cf\u5439\u5411\u7b2c\u4e8c\u5f20\u5361\uff0c\u5bfc\u81f4\u7b2c\u4e8c\u5f20\u5361\u6e29\u5ea6\u8fc7\u9ad8\uff0c\u5f71\u54cd\u6027\u80fd\u3002 \u98ce\u6247\u663e\u5361\u5f88\u6709\u53ef\u80fd\u662f\u8d85\u8fc7\u53cc\u69fd\u5bbd\u7684\uff0c\u7b2c\u4e8c\u5f20\u5361\u53ef\u80fd\u63d2\u4e0d\u4e0a\u7b2c\u4e8c\u4e2a PCI-E \u63d2\u69fd\uff0c\u8fd9\u4e2a\u4e5f\u9700\u8981\u6ce8\u610f\u3002 \u6da1\u8f6e\uff1a \u7d22\u6cf0 GeForce\u00ae RTX2080-8GD6 AI\u7248 OC HA \u98ce\u6247\uff1a \u534e\u7855 ROG \u731b\u79bd\u7cfb\u5217 GeForce RTX\u2122 2080 Ti OC\u7248","title":"\u6da1\u8f6e\u4e0e\u98ce\u6247"},{"location":"how-to-build-deep-learning-workstation/#_8","text":"","title":"\u786c\u76d8"},{"location":"how-to-build-deep-learning-workstation/#_9","text":"\u5e38\u7528\u786c\u76d8\u63a5\u53e3\u6709\u4e09\u79cd\uff1a SATA3.0\uff0c\u901f\u5ea6 600MB/s SAS\uff0c\u901f\u5ea6 1200MB/s PCIE 3.0 x4\uff08NVMe\uff09\uff0c\u901f\u5ea6 3.93GB/s PCIE 4.0 x4\uff08NVMe\uff09\uff0c\u901f\u5ea6 7.87GB/s","title":"\u786c\u76d8\u7c7b\u578b"},{"location":"how-to-build-deep-learning-workstation/#_10","text":"\u4e0b\u9762\u662f\u6839\u636e\u4ee3\u8868\u4ea7\u54c1\u67e5\u8be2\u7684\u53c2\u6570\uff1a \u7c7b\u578b \u4ef7\u683c(\u5143/TB) \u8bfb\u53d6\u901f\u5ea6(MB/s) \u5199\u5165\u901f\u5ea6 4K\u968f\u673a\u8bfb\u53d6(IOPS) 4K\u968f\u673a\u5199\u5165(IOPS) SATA3 \u673a\u68b0\u786c\u76d8 150 270 258 170 550 SATA3 \u56fa\u6001\u786c\u76d8 700 560 530 98000 88000 NVMe \u56fa\u6001\u786c\u76d8 800 3500 3000 500000 480000 \u6ce8\uff1a SATA3 \u673a\u68b0\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a Seagate Exos X18 ST18000NM000J SATA3 \u56fa\u6001\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a 870 QVO SATA 2.5\u82f1\u5bf8 \u56fa\u6001\u786c\u76d8 NVMe \u56fa\u6001\u786c\u76d8\u6570\u636e\u6765\u6e90\uff1a 980 NVMe\u2122 M.2 \u56fa\u6001\u786c\u76d8 \u5728\u9762\u5bf9\u5927\u91cf\u5c0f\u6587\u4ef6\u7684\u65f6\u5019\uff0c\u4f7f\u7528 NVMe \u786c\u76d8\u53ef\u4ee5\u4e00\u5206\u949f\u626b\u5b8c 1000\u4e07\u6587\u4ef6\uff0c\u5982\u679c\u4f7f\u7528\u666e\u901a\u786c\u76d8\uff0c\u90a3\u4e48\u5c31\u9700\u8981\u4e00\u5929\u65f6\u95f4\u3002\u4e3a\u4e86\u8282\u7701\u751f\u547d\uff0c\u7b80\u5316\u4ee3\u7801\uff0c\u786c\u76d8\u5efa\u8bae\u9009\u62e9 NVMe \u534f\u8bae\u7684\u56fa\u6001\u786c\u76d8\u3002 \u5982\u679c\u4f60\u7684\u4e3b\u677f\u4e0d\u591f\u65b0\uff0c\u6ca1\u6709 NVMe \u63d2\u69fd\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 M.2 \u8f6c\u63a5\u5361\u5c06 M.2 \u63a5\u53e3\u8f6c\u4e3a PCI-E \u63a5\u53e3\u3002","title":"\u53c2\u6570\u5bf9\u6bd4"},{"location":"how-to-build-deep-learning-workstation/#_11","text":"\u5185\u5b58\u5bb9\u91cf\u7684\u9009\u62e9\u901a\u5e38\u5927\u4e8e\u663e\u5b58\uff0c\u6bd4\u5982\u5355\u5361\u914d 16GB \u5185\u5b58\uff0c\u56db\u5361\u914d 64GB \u5185\u5b58\u3002\u7531\u4e8e\u6709\u6570\u636e\u751f\u6210\u5668\uff08DataLoader\uff09\uff0c\u6570\u636e\u4e0d\u5fc5\u5168\u90e8\u52a0\u8f7d\u5230\u5185\u5b58\u91cc\uff0c\u901a\u5e38\u4e0d\u4f1a\u6210\u4e3a\u74f6\u9888\u3002","title":"\u5185\u5b58"},{"location":"how-to-build-deep-learning-workstation/#_12","text":"\u5148\u8ba1\u7b97\u529f\u7387\u603b\u548c\uff0c\u5982\u5355\u5361 CPU 250W\uff0c\u663e\u5361 350W\uff0c\u52a0\u4e0a\u5176\u4ed6\u7684\u5927\u6982 200W\uff0c\u90a3\u4e48\u5c31\u4e70 850W \u7684\u7535\u6e90\u3002 \u53cc\u5361\u6700\u597d\u4e70 1200W \u4ee5\u4e0a\u7684\u7535\u6e90\uff0c\u56db\u5361\u6700\u597d\u4e70 2000W \u7684\u7535\u6e90\u3002\u5982\u679c\u7535\u6e90\u4e0d\u591f\uff0c\u8dd1\u8d77\u6765\u6240\u6709\u7684\u5361\u4ee5\u540e\u4f1a\u56e0\u4e3a\u7535\u6e90\u4e0d\u8db3\u800c\u81ea\u52a8\u5173\u673a\u3002 \u4e00\u822c\u5899\u4e0a\u7684\u63d2\u5ea7\u53ea\u652f\u6301 220V 10A\uff0c\u4e5f\u5c31\u662f 2200W \u7684\u4ea4\u6d41\u7535\uff0c\u7531\u4e8e\u7535\u6e90\u8981\u628a\u4ea4\u6d41\u7535\u8f6c\u76f4\u6d41\u7535\uff0c\u6240\u4ee5\u4f1a\u6709\u4e00\u4e9b\u635f\u8017\uff0c\u6700\u9ad8\u53ea\u6709 2000W\uff0c\u56e0\u6b64\u5982\u679c\u60f3\u8981\u652f\u6301\u516b\u5361\uff0c\u6700\u597d\u4e0d\u8981\u5728\u5bb6\u5c1d\u8bd5\u3002\u516b\u5361\u4e00\u822c\u662f\u56db\u4e2a PDU \u7535\u6e90\uff0c\u5e76\u4e14\u7535\u6d41\u5f88\u5927\uff0c\u6240\u4ee5\u9700\u8981\u4e13\u95e8\u8d70\u7ebf\uff0c\u5982\u679c\u5728\u5bb6\u76f4\u63a5\u4ece\u5899\u4e0a\u63a5\u63d2\u5ea7\uff0c\u7136\u540e\u63d2\u56db\u4e2a\u7535\u6e90\uff0c\u5bb9\u6613\u5f15\u53d1\u706b\u707e\u3002","title":"\u7535\u6e90"},{"location":"how-to-build-deep-learning-workstation/#_13","text":"\u4e00\u822c\u4e3b\u677f\u81ea\u5e26\u5343\u5146\u7f51\u5361\u3002\u5982\u679c\u9700\u8981\u7ec4\u5efa\u591a\u673a\u591a\u5361\u96c6\u7fa4\uff0c\u8bf7\u8054\u7cfb\u4f9b\u5e94\u5546\u54a8\u8be2\u4e13\u4e1a\u7684\u89e3\u51b3\u65b9\u6848\u3002","title":"\u7f51\u5361"},{"location":"how-to-build-deep-learning-workstation/#_14","text":"\u5982\u679c\u914d\u5355\u5361\uff0c\u53ef\u4ee5\u76f4\u63a5\u4e70\u4e2a\u666e\u901a\u4e2d\u5854\u673a\u7bb1\uff0c\u6ce8\u610f\u663e\u5361\u957f\u5ea6\u80fd\u653e\u4e0b\u5c31\u884c\u3002 \u5982\u679c\u914d\u56db\u5361\u673a\u5668\uff0c\u5efa\u8bae\u4e70\u4e00\u4e2a\u5168\u5854\u673a\u7bb1\u3002 \u4e0b\u56fe\u662f\u6211\u642d\u5efa\u56db\u5361\u65f6\u4f7f\u7528\u7684\u673a\u7bb1\uff0c\u73b0\u5728\u5df2\u7ecf\u505c\u4ea7\u4e86\u3002","title":"\u673a\u7bb1"},{"location":"how-to-build-deep-learning-workstation/#_15","text":"\u6df1\u5ea6\u5b66\u4e60\u5de5\u4f5c\u7ad9\u88c5\u597d\u7cfb\u7edf\u4ee5\u540e\u5c31\u4e0d\u9700\u8981\u663e\u793a\u5668\u548c\u952e\u9f20\u5957\u88c5\u4e86\uff0c\u88c5\u7cfb\u7edf\u7684\u65f6\u5019\u4f7f\u7528\u624b\u8fb9\u7684\u663e\u793a\u5668\u548c\u952e\u76d8\u9f20\u6807\u5c31\u884c\u3002 \u6211\u4eec\u4e00\u822c\u4f1a\u5728\u6df1\u5ea6\u5b66\u4e60\u673a\u5668\u4e0a\u5b89\u88c5 Linux \u7cfb\u7edf\uff0c\u7136\u540e\u901a\u8fc7 Mac \u8fdc\u7a0b\u8fde\u63a5\uff0c\u901a\u8fc7 PyCharm \u8fdc\u7a0b\u8c03\u8bd5\uff0c\u6240\u4ee5\u4e3b\u673a\u53ea\u9700\u8981\u63d2\u7535\u548c\u63d2\u7f51\u7ebf\u5373\u53ef\uff0c\u4e0d\u9700\u8981\u8fde\u63a5\u663e\u793a\u5668\u548c\u952e\u76d8\u9f20\u6807\u3002","title":"\u663e\u793a\u5668\u4e0e\u952e\u76d8\u9f20\u6807"},{"location":"how-to-use-tensorboard/","text":"\u5982\u4f55\u4f7f\u7528 TensorBoard \u672c\u6587\u4f1a\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528 tensorboard \u8fdb\u884c\u53ef\u89c6\u5316\u3002 \u5b89\u88c5 \u5728\u4f7f\u7528\u4e4b\u524d\uff0c\u53ef\u4ee5\u5148\u770b\u770b \u73af\u5883\u914d\u7f6e--tensorboard \u3002 \u4e3a\u4e86\u5728 PyTorch \u91cc\u6109\u5feb\u5730\u4f7f\u7528 TensorBoard\uff0c\u76ee\u524d\u5efa\u8bae\u4f7f\u7528 tensorboardX \u5199\u51fa events.out \u6587\u4ef6\u3002 \u4e0b\u9762\u662f\u5b89\u88c5\u547d\u4ee4\uff1a pip install tensorboard tensorboardx \u4f7f\u7528 \u4e07\u53d8\u4e0d\u79bb\u5176\u5b97\uff0c\u4f7f\u7528\u65b9\u6cd5\u9996\u5148\u5e94\u8be5\u67e5\u770b\u6587\u6863\uff1a https://tensorboardx.readthedocs.io/en/latest/tensorboard.html \u8fd9\u91cc\u6211\u4ee5 PyTorch \u8bad\u7ec3 CRNN \u6a21\u578b\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u5982\u4f55\u53ef\u89c6\u5316\u4ee5\u4e0b\u51e0\u4e2a\u5185\u5bb9\uff1a \u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784 \u6309 epoch \u53ef\u89c6\u5316 loss\u3001acc \u6309 batch \u53ef\u89c6\u5316 loss\u3001acc \u53ef\u89c6\u5316\u8bad\u7ec3\u8fc7\u7a0b\u4e2d loss \u6bd4\u8f83\u9ad8\u7684\u6837\u672c\uff08badcase\uff09 \u4f7f\u7528 TensorBoard \u9700\u8981\u505a\u4ee5\u4e0b\u4e24\u4ef6\u4e8b\uff1a \u5728\u4ee3\u7801\u4e2d\u5bf9\u9700\u8981\u53ef\u89c6\u5316\u7684\u5730\u65b9\u6dfb\u52a0\u5199\u51fa\u4ee3\u7801 \u6253\u5f00 TensorBoard \u670d\u52a1 \u521b\u5efa\u6587\u4ef6\u5bf9\u8c61\uff08writer\uff09 import time from tensorboardX import SummaryWriter now = time . strftime ( \"%Y%m %d _%H%M%S\" , time . localtime ()) model_name = f 'crnn_ { now } ' print ( model_name ) writer = SummaryWriter ( f 'logs/ { model_name } ' ) \u4f7f\u7528\u4e0a\u9762\u7684\u4ee3\u7801\u5373\u53ef\u521b\u5efa\u4e00\u4e2a writer \u5bf9\u8c61\uff0c\u4e4b\u540e\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a writer \u5199\u51fa\u6211\u4eec\u60f3\u8981\u5199\u51fa\u7684\u4e1c\u897f\u3002 \u8bad\u7ec3\u4e00\u6bb5\u65f6\u95f4\u4ee5\u540e\uff0c\u4f1a\u5728 logs \u6587\u4ef6\u5939\u4e0b\u6784\u5efa\u4ee5\u4e0b\u6587\u4ef6\u7ed3\u6784\uff1a logs \u2514\u2500\u2500 crnn_20190630_200056 \u251c\u2500\u2500 epoch \u2502 \u251c\u2500\u2500 acc \u2502 \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2502 \u2514\u2500\u2500 valid \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u251c\u2500\u2500 error_rate \u2502 \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2502 \u2514\u2500\u2500 valid \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2514\u2500\u2500 loss \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2514\u2500\u2500 valid \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2514\u2500\u2500 events.out.tfevents.1561896056.ypw-black \u6253\u5f00 TensorBoard \u670d\u52a1 \u5b89\u88c5\u4e86 TensorBoard \u4ee5\u540e\uff0c\u76f4\u63a5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5c31\u53ef\u4ee5\u6253\u5f00 TensorBoard \u670d\u52a1\uff1a tensorboard --logdir = logs \u5047\u8bbe\u4f60\u7684\u670d\u52a1\u5668 IP \u5730\u5740\u662f 192.168.8.100\uff0c\u53ea\u9700\u8981\u5728\u6d4f\u89c8\u5668\u91cc\u8f93\u5165 http://192.168.8.100:6006 \u5c31\u53ef\u4ee5\u6253\u5f00 TensorBoard \u9762\u677f\u3002 \u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784 \u6a21\u578b\u7ed3\u6784\u7684\u53ef\u89c6\u5316\u975e\u5e38\u7b80\u5355\uff0c\u53ea\u9700\u8981\u6784\u5efa\u4e00\u4e2a\u8f93\u5165 tensor \u5373\u53ef\uff1a model = Model ( n_classes , input_shape = ( 3 , height , width )) inputs = torch . zeros (( 1 , 3 , height , width )) writer . add_graph ( model , inputs ) \u7136\u540e\u4f60\u5c31\u53ef\u4ee5\u5728 http://192.168.8.100:6006/#graphs \u91cc\u770b\u5230\u4f60\u7684\u6a21\u578b\u7ed3\u6784\u3002 \u53cc\u51fb Model \u5c31\u53ef\u4ee5\u5c55\u5f00\u5b83\uff0c\u4e0b\u9762\u662f\u5c55\u5f00\u5230\u5408\u7406\u7a0b\u5ea6\u7684\u6a21\u578b\u7ed3\u6784\u56fe\uff1a \u8bb0\u5f55\u6807\u91cf\uff08scalar\uff09 \u4f7f\u7528 writer.add_scalar \u5c31\u80fd\u8f7b\u677e\u753b\u51fa loss \u66f2\u7ebf\uff0c\u4e0b\u9762\u662f\u7ecf\u8fc7\u7b80\u5316\u7684\u8bad\u7ec3\u51fd\u6570\uff1a def train ( model , optimizer , epoch , dataloader , writer ): # ... for batch_index , ( data , target ) in enumerate ( pbar ): # ... output = model ( data ) loss = criterion ( output , target ) acc = calc_acc ( target , output ) # ... iteration = ( epoch - 1 ) * len ( dataloader ) + batch_index writer . add_scalar ( 'train/loss' , loss , iteration ) writer . add_scalar ( 'train/acc' , acc , iteration ) writer . add_scalar ( 'train/error_rate' , 1 - acc , iteration ) \u4e3a\u4e86\u8ba9\u591a\u4e2a\u56fe\u7ed8\u5236\u5728\u4e00\u4e2a\u6807\u7b7e\u4e0b\uff0c\u659c\u6760\u524d\u9762\u7684\u540d\u79f0\u9700\u8981\u7edf\u4e00\uff0c\u6211\u8fd9\u91cc\u4ee5 train/ \u8868\u793a\uff0c\u5728 TensorBoard \u91cc\u5c31\u53ef\u4ee5\u7edf\u4e00\u7ed8\u5236\u5728 train \u8fd9\u4e2a\u6807\u7b7e\u5185\uff0c\u5c55\u5f00\u548c\u5408\u5e76\u90fd\u6bd4\u8f83\u65b9\u4fbf\u3002 \u8bad\u7ec3\u5b8c\u4ee5\u540e\u7684\u66f2\u7ebf\u5982\u56fe\uff1a \u8fd9\u91cc\u6709\u4e00\u4e2a\u5c0f\u6280\u5de7\uff0c\u5982\u679c\u4f60\u60f3\u53ef\u89c6\u5316\u6b63\u786e\u7387\u8fd9\u79cd\u63a5\u8fd1 1 \u7684\u6307\u6807\uff0c\u6700\u597d\u4f7f\u7528\u9519\u8bef\u7387\uff081\u51cf\u6b63\u786e\u7387\uff09\uff0c\u56e0\u4e3a\u5f53\u6b63\u786e\u7387\u975e\u5e38\u63a5\u8fd1 1 \u7684\u65f6\u5019\uff0c\u5f88\u96be\u770b\u51fa\u6765\u8d8b\u52bf\u3002\u4f7f\u7528 TensorBoard \u5207\u6362\u5230\u5bf9\u6570\u5c3a\u5ea6\u4e0b\uff0c\u5c31\u80fd\u8f7b\u677e\u770b\u51fa\u9519\u8bef\u7387\u7684\u8d8b\u52bf\u4e86\uff1a \u5728 30k \u7684\u65f6\u5019\uff0c\u6211\u628a\u5b66\u4e60\u7387\u964d\u4f4e\u4e86 10\u500d\uff0c\u7ee7\u7eed\u8bad\u7ec3\u4e86 10\u4ee3\uff0c\u5982\u679c\u770b\u4e0a\u9762\u7684\u56fe\uff0c\u53ea\u80fd\u770b\u51fa\u6765 loss \u66f4\u5e73\u7f13\u4e86\uff0c\u4f46\u662f\u4e0b\u9762\u7684\u5bf9\u6570\u5c3a\u5ea6\u4e0b\u5c31\u53ef\u4ee5\u660e\u663e\u770b\u51fa\u6765 loss \u4ece 8e-3 \u4e0b\u964d\u5230\u4e86 2e-3\uff0c\u4e0b\u964d\u4e86 4 \u500d\u3002 \u8bb0\u5f55\u591a\u4e2a\u6807\u91cf\uff08scalars\uff09 \u5f88\u591a\u65f6\u5019\u6211\u4eec\u90fd\u9700\u8981\u4f7f\u7528\u8bad\u7ec3\u96c6\u7684 loss \u548c\u9a8c\u8bc1\u96c6\u7684 loss \u505a\u5bf9\u6bd4\uff0c\u4ee5\u5224\u65ad\u6a21\u578b\u6709\u6ca1\u6709\u8fc7\u62df\u5408\u3002\u8fd9\u65f6\u5019\u4f7f\u7528 writer.add_scalars \u5c31\u53ef\u4ee5\u5c06\u591a\u4e2a\u6807\u91cf\u7ed8\u5236\u5728\u540c\u4e00\u5f20\u56fe\u91cc\u8fdb\u884c\u5bf9\u6bd4\u3002\u4e0b\u9762\u662f\u793a\u4f8b\u4ee3\u7801\uff1a for epoch in range ( 1 , epochs + 1 ): train_loss , train_acc = train ( model , optimizer , epoch , train_loader , writer ) valid_loss , valid_acc = valid ( model , epoch , valid_loader , writer ) writer . add_scalars ( 'epoch/loss' , { 'train' : train_loss , 'valid' : valid_loss }, epoch ) writer . add_scalars ( 'epoch/acc' , { 'train' : train_acc , 'valid' : valid_acc }, epoch ) writer . add_scalars ( 'epoch/error_rate' , { 'train' : 1 - train_acc , 'valid' : 1 - valid_acc }, epoch ) \u53ef\u4ee5\u770b\u5230\u5728\u5bf9\u6570\u5c3a\u5ea6\u4e0b\uff0closs \u548c\u9519\u8bef\u7387\u8fd8\u6709\u5411\u4e0b\u8d70\u7684\u8d8b\u52bf\uff0c\u53ef\u4ee5\u7ee7\u7eed\u8bad\u7ec3\u3002 \u8bb0\u5f55\u56fe\u50cf\uff08images\uff09 \u4e0d\u7ba1\u662f\u5728 GAN \u91cc\uff0c\u8fd8\u662f\u5176\u4ed6\u56fe\u50cf\u4efb\u52a1\u91cc\uff0c\u7ed8\u5236\u56fe\u50cf\u90fd\u662f\u4e00\u4e2a\u5f88\u6709\u7528\u7684\u529f\u80fd\u3002\u4e0b\u9762\u6211\u4ee5\u7ed8\u5236 badcase \u4e3a\u4f8b\uff1a # draw badcase with torch . no_grad (): output_argmax = output . detach () . permute ( 1 , 0 , 2 ) . argmax ( dim =- 1 ) loss = F . ctc_loss ( output_log_softmax , target , input_lengths , target_lengths , reduction = 'none' ) hard_sample = np . argsort ( loss . detach () . cpu () . numpy ())[:: - 1 ] data = data . cpu () target = target . cpu () nrow = 4 ncol = 4 fig = plt . figure ( figsize = ( 12 , 6 )) for i , index in enumerate ( hard_sample [: nrow * ncol ]): plt . subplot ( ncol , nrow , i + 1 ) plt . axis ( 'off' ) plt . imshow ( data [ index ] . numpy () . transpose ( 1 , 2 , 0 )) s = f 'true: { decode_target ( target [ index ]) } \\n pred: { decode ( output_argmax [ index ]) } ' plt . title ( s ) fig . canvas . draw () image = np . array ( fig . canvas . renderer . buffer_rgba ()) plt . close () writer . add_image ( 'train/badcase' , to_tensor ( image ), epoch ) \u9996\u5148\u4e3a\u4e86\u907f\u514d\u5f71\u54cd\u8bad\u7ec3\uff0c\u6574\u4e2a\u4ee3\u7801\u90fd\u9700\u8981\u5728 torch.no_grad() \u4e0b\u8fdb\u884c\u3002\u7136\u540e\u4e3a\u4e86\u83b7\u53d6\u4e0d\u597d\u8bc6\u522b\u7684\u6837\u672c\uff0c\u9700\u8981\u91cd\u65b0\u8ba1\u7b97 loss\uff0c\u5e76\u4e14\u6dfb\u52a0 reduction='none' \u4ee5\u8ba1\u7b97\u6bcf\u4e2a\u6837\u672c\u7684 loss\u3002 OCR \u95ee\u9898\u65e2\u9700\u8981\u56fe\u50cf\uff0c\u53c8\u9700\u8981\u6587\u672c\uff0c\u6240\u4ee5\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528 matplotlib \u7ed8\u5236\u56fe\u50cf\uff0c\u7136\u540e\u5f97\u5230\u77e9\u9635\u6bd4\u8f83\u65b9\u4fbf\u3002\u5982\u679c\u4f60\u53ea\u60f3\u62fc\u63a5\u591a\u4e2a\u56fe\u50cf\uff0c\u53ef\u4ee5\u4f7f\u7528 from torchvision.utils import make_grid \u51fd\u6570\u3002 \u4e0b\u9762\u662f\u8bad\u7ec3\u8fc7\u7a0b\u4e2d\u7684 badcase\uff1a \u53ef\u4ee5\u770b\u5230\u5927\u90e8\u5206\u56fe\u50cf\u90fd\u662f\u56e0\u4e3a 0 \u548c O \u8bc6\u522b\u4e0d\u5bf9\uff0c\u5176\u5b9e\u524d\u9762\u51e0\u4e2a\u56fe\u6211\u4e5f\u770b\u4e0d\u51fa\u6765\u5230\u5e95\u662f 0 \u8fd8\u662f O\u3002 \u5b8c\u6574\u4ee3\u7801 \u4ee5\u4e0a\u51e0\u4e2a\u4f8b\u5b50\u7684\u5b8c\u6574\u4ee3\u7801\u5728 https://github.com/ypwhs/captcha_break \u9879\u76ee\u4e2d\uff0c\u6587\u4ef6\u540d\u662f ctc_pytorch_tensorboard.ipynb \uff0c\u8be5\u9879\u76ee\u89e3\u51b3\u4e86\u9a8c\u8bc1\u7801\u8bc6\u522b\u7684\u95ee\u9898\uff0c\u6700\u7ec8\u8bad\u7ec3\u5230\u4e86 0.9957 \u7684\u51c6\u786e\u7387\u3002 \u603b\u7ed3 \u4f7f\u7528 TensorBoard \u53ef\u4ee5\u76d1\u63a7\u8bad\u7ec3\u8fc7\u7a0b\u4e2d\u7684 loss \u8d8b\u52bf\uff0c\u53ca\u65e9\u53d1\u73b0\u95ee\u9898\u3002\u8bad\u7ec3\u591a\u4e2a\u6a21\u578b\u4ee5\u540e\uff0c\u8fd8\u53ef\u4ee5\u628a\u591a\u4e2a\u6a21\u578b\u7684\u66f2\u7ebf\u653e\u5728\u4e00\u5f20\u56fe\u91cc\u6a2a\u5411\u5bf9\u6bd4\u3002\u53e6\u5916 badcase \u5206\u6790\u4e5f\u53ef\u4ee5\u53d1\u73b0\u66f4\u591a\u6f5c\u5728\u7684\u95ee\u9898\uff0c\u4e3a\u4e4b\u540e\u7684\u4f18\u5316\u5bfb\u627e\u65b9\u5411\u3002\u53ef\u4ee5\u8bf4 TensorBoard \u662f\u6bcf\u4e00\u4e2a\u6df1\u5ea6\u5b66\u4e60\u4ece\u4e1a\u8005\u7684\u5fc5\u5907\u6280\u80fd\u3002","title":"\u5982\u4f55\u4f7f\u7528 TensorBoard"},{"location":"how-to-use-tensorboard/#tensorboard","text":"\u672c\u6587\u4f1a\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528 tensorboard \u8fdb\u884c\u53ef\u89c6\u5316\u3002","title":"\u5982\u4f55\u4f7f\u7528 TensorBoard"},{"location":"how-to-use-tensorboard/#_1","text":"\u5728\u4f7f\u7528\u4e4b\u524d\uff0c\u53ef\u4ee5\u5148\u770b\u770b \u73af\u5883\u914d\u7f6e--tensorboard \u3002 \u4e3a\u4e86\u5728 PyTorch \u91cc\u6109\u5feb\u5730\u4f7f\u7528 TensorBoard\uff0c\u76ee\u524d\u5efa\u8bae\u4f7f\u7528 tensorboardX \u5199\u51fa events.out \u6587\u4ef6\u3002 \u4e0b\u9762\u662f\u5b89\u88c5\u547d\u4ee4\uff1a pip install tensorboard tensorboardx","title":"\u5b89\u88c5"},{"location":"how-to-use-tensorboard/#_2","text":"\u4e07\u53d8\u4e0d\u79bb\u5176\u5b97\uff0c\u4f7f\u7528\u65b9\u6cd5\u9996\u5148\u5e94\u8be5\u67e5\u770b\u6587\u6863\uff1a https://tensorboardx.readthedocs.io/en/latest/tensorboard.html \u8fd9\u91cc\u6211\u4ee5 PyTorch \u8bad\u7ec3 CRNN \u6a21\u578b\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u5982\u4f55\u53ef\u89c6\u5316\u4ee5\u4e0b\u51e0\u4e2a\u5185\u5bb9\uff1a \u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784 \u6309 epoch \u53ef\u89c6\u5316 loss\u3001acc \u6309 batch \u53ef\u89c6\u5316 loss\u3001acc \u53ef\u89c6\u5316\u8bad\u7ec3\u8fc7\u7a0b\u4e2d loss \u6bd4\u8f83\u9ad8\u7684\u6837\u672c\uff08badcase\uff09 \u4f7f\u7528 TensorBoard \u9700\u8981\u505a\u4ee5\u4e0b\u4e24\u4ef6\u4e8b\uff1a \u5728\u4ee3\u7801\u4e2d\u5bf9\u9700\u8981\u53ef\u89c6\u5316\u7684\u5730\u65b9\u6dfb\u52a0\u5199\u51fa\u4ee3\u7801 \u6253\u5f00 TensorBoard \u670d\u52a1","title":"\u4f7f\u7528"},{"location":"how-to-use-tensorboard/#writer","text":"import time from tensorboardX import SummaryWriter now = time . strftime ( \"%Y%m %d _%H%M%S\" , time . localtime ()) model_name = f 'crnn_ { now } ' print ( model_name ) writer = SummaryWriter ( f 'logs/ { model_name } ' ) \u4f7f\u7528\u4e0a\u9762\u7684\u4ee3\u7801\u5373\u53ef\u521b\u5efa\u4e00\u4e2a writer \u5bf9\u8c61\uff0c\u4e4b\u540e\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a writer \u5199\u51fa\u6211\u4eec\u60f3\u8981\u5199\u51fa\u7684\u4e1c\u897f\u3002 \u8bad\u7ec3\u4e00\u6bb5\u65f6\u95f4\u4ee5\u540e\uff0c\u4f1a\u5728 logs \u6587\u4ef6\u5939\u4e0b\u6784\u5efa\u4ee5\u4e0b\u6587\u4ef6\u7ed3\u6784\uff1a logs \u2514\u2500\u2500 crnn_20190630_200056 \u251c\u2500\u2500 epoch \u2502 \u251c\u2500\u2500 acc \u2502 \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2502 \u2514\u2500\u2500 valid \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u251c\u2500\u2500 error_rate \u2502 \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2502 \u2514\u2500\u2500 valid \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2514\u2500\u2500 loss \u2502 \u251c\u2500\u2500 train \u2502 \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2502 \u2514\u2500\u2500 valid \u2502 \u2514\u2500\u2500 events.out.tfevents.1561896176.ypw-black \u2514\u2500\u2500 events.out.tfevents.1561896056.ypw-black","title":"\u521b\u5efa\u6587\u4ef6\u5bf9\u8c61\uff08writer\uff09"},{"location":"how-to-use-tensorboard/#tensorboard_1","text":"\u5b89\u88c5\u4e86 TensorBoard \u4ee5\u540e\uff0c\u76f4\u63a5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5c31\u53ef\u4ee5\u6253\u5f00 TensorBoard \u670d\u52a1\uff1a tensorboard --logdir = logs \u5047\u8bbe\u4f60\u7684\u670d\u52a1\u5668 IP \u5730\u5740\u662f 192.168.8.100\uff0c\u53ea\u9700\u8981\u5728\u6d4f\u89c8\u5668\u91cc\u8f93\u5165 http://192.168.8.100:6006 \u5c31\u53ef\u4ee5\u6253\u5f00 TensorBoard \u9762\u677f\u3002","title":"\u6253\u5f00 TensorBoard \u670d\u52a1"},{"location":"how-to-use-tensorboard/#_3","text":"\u6a21\u578b\u7ed3\u6784\u7684\u53ef\u89c6\u5316\u975e\u5e38\u7b80\u5355\uff0c\u53ea\u9700\u8981\u6784\u5efa\u4e00\u4e2a\u8f93\u5165 tensor \u5373\u53ef\uff1a model = Model ( n_classes , input_shape = ( 3 , height , width )) inputs = torch . zeros (( 1 , 3 , height , width )) writer . add_graph ( model , inputs ) \u7136\u540e\u4f60\u5c31\u53ef\u4ee5\u5728 http://192.168.8.100:6006/#graphs \u91cc\u770b\u5230\u4f60\u7684\u6a21\u578b\u7ed3\u6784\u3002 \u53cc\u51fb Model \u5c31\u53ef\u4ee5\u5c55\u5f00\u5b83\uff0c\u4e0b\u9762\u662f\u5c55\u5f00\u5230\u5408\u7406\u7a0b\u5ea6\u7684\u6a21\u578b\u7ed3\u6784\u56fe\uff1a","title":"\u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784"},{"location":"how-to-use-tensorboard/#scalar","text":"\u4f7f\u7528 writer.add_scalar \u5c31\u80fd\u8f7b\u677e\u753b\u51fa loss \u66f2\u7ebf\uff0c\u4e0b\u9762\u662f\u7ecf\u8fc7\u7b80\u5316\u7684\u8bad\u7ec3\u51fd\u6570\uff1a def train ( model , optimizer , epoch , dataloader , writer ): # ... for batch_index , ( data , target ) in enumerate ( pbar ): # ... output = model ( data ) loss = criterion ( output , target ) acc = calc_acc ( target , output ) # ... iteration = ( epoch - 1 ) * len ( dataloader ) + batch_index writer . add_scalar ( 'train/loss' , loss , iteration ) writer . add_scalar ( 'train/acc' , acc , iteration ) writer . add_scalar ( 'train/error_rate' , 1 - acc , iteration ) \u4e3a\u4e86\u8ba9\u591a\u4e2a\u56fe\u7ed8\u5236\u5728\u4e00\u4e2a\u6807\u7b7e\u4e0b\uff0c\u659c\u6760\u524d\u9762\u7684\u540d\u79f0\u9700\u8981\u7edf\u4e00\uff0c\u6211\u8fd9\u91cc\u4ee5 train/ \u8868\u793a\uff0c\u5728 TensorBoard \u91cc\u5c31\u53ef\u4ee5\u7edf\u4e00\u7ed8\u5236\u5728 train \u8fd9\u4e2a\u6807\u7b7e\u5185\uff0c\u5c55\u5f00\u548c\u5408\u5e76\u90fd\u6bd4\u8f83\u65b9\u4fbf\u3002 \u8bad\u7ec3\u5b8c\u4ee5\u540e\u7684\u66f2\u7ebf\u5982\u56fe\uff1a \u8fd9\u91cc\u6709\u4e00\u4e2a\u5c0f\u6280\u5de7\uff0c\u5982\u679c\u4f60\u60f3\u53ef\u89c6\u5316\u6b63\u786e\u7387\u8fd9\u79cd\u63a5\u8fd1 1 \u7684\u6307\u6807\uff0c\u6700\u597d\u4f7f\u7528\u9519\u8bef\u7387\uff081\u51cf\u6b63\u786e\u7387\uff09\uff0c\u56e0\u4e3a\u5f53\u6b63\u786e\u7387\u975e\u5e38\u63a5\u8fd1 1 \u7684\u65f6\u5019\uff0c\u5f88\u96be\u770b\u51fa\u6765\u8d8b\u52bf\u3002\u4f7f\u7528 TensorBoard \u5207\u6362\u5230\u5bf9\u6570\u5c3a\u5ea6\u4e0b\uff0c\u5c31\u80fd\u8f7b\u677e\u770b\u51fa\u9519\u8bef\u7387\u7684\u8d8b\u52bf\u4e86\uff1a \u5728 30k \u7684\u65f6\u5019\uff0c\u6211\u628a\u5b66\u4e60\u7387\u964d\u4f4e\u4e86 10\u500d\uff0c\u7ee7\u7eed\u8bad\u7ec3\u4e86 10\u4ee3\uff0c\u5982\u679c\u770b\u4e0a\u9762\u7684\u56fe\uff0c\u53ea\u80fd\u770b\u51fa\u6765 loss \u66f4\u5e73\u7f13\u4e86\uff0c\u4f46\u662f\u4e0b\u9762\u7684\u5bf9\u6570\u5c3a\u5ea6\u4e0b\u5c31\u53ef\u4ee5\u660e\u663e\u770b\u51fa\u6765 loss \u4ece 8e-3 \u4e0b\u964d\u5230\u4e86 2e-3\uff0c\u4e0b\u964d\u4e86 4 \u500d\u3002","title":"\u8bb0\u5f55\u6807\u91cf\uff08scalar\uff09"},{"location":"how-to-use-tensorboard/#scalars","text":"\u5f88\u591a\u65f6\u5019\u6211\u4eec\u90fd\u9700\u8981\u4f7f\u7528\u8bad\u7ec3\u96c6\u7684 loss \u548c\u9a8c\u8bc1\u96c6\u7684 loss \u505a\u5bf9\u6bd4\uff0c\u4ee5\u5224\u65ad\u6a21\u578b\u6709\u6ca1\u6709\u8fc7\u62df\u5408\u3002\u8fd9\u65f6\u5019\u4f7f\u7528 writer.add_scalars \u5c31\u53ef\u4ee5\u5c06\u591a\u4e2a\u6807\u91cf\u7ed8\u5236\u5728\u540c\u4e00\u5f20\u56fe\u91cc\u8fdb\u884c\u5bf9\u6bd4\u3002\u4e0b\u9762\u662f\u793a\u4f8b\u4ee3\u7801\uff1a for epoch in range ( 1 , epochs + 1 ): train_loss , train_acc = train ( model , optimizer , epoch , train_loader , writer ) valid_loss , valid_acc = valid ( model , epoch , valid_loader , writer ) writer . add_scalars ( 'epoch/loss' , { 'train' : train_loss , 'valid' : valid_loss }, epoch ) writer . add_scalars ( 'epoch/acc' , { 'train' : train_acc , 'valid' : valid_acc }, epoch ) writer . add_scalars ( 'epoch/error_rate' , { 'train' : 1 - train_acc , 'valid' : 1 - valid_acc }, epoch ) \u53ef\u4ee5\u770b\u5230\u5728\u5bf9\u6570\u5c3a\u5ea6\u4e0b\uff0closs \u548c\u9519\u8bef\u7387\u8fd8\u6709\u5411\u4e0b\u8d70\u7684\u8d8b\u52bf\uff0c\u53ef\u4ee5\u7ee7\u7eed\u8bad\u7ec3\u3002","title":"\u8bb0\u5f55\u591a\u4e2a\u6807\u91cf\uff08scalars\uff09"},{"location":"how-to-use-tensorboard/#images","text":"\u4e0d\u7ba1\u662f\u5728 GAN \u91cc\uff0c\u8fd8\u662f\u5176\u4ed6\u56fe\u50cf\u4efb\u52a1\u91cc\uff0c\u7ed8\u5236\u56fe\u50cf\u90fd\u662f\u4e00\u4e2a\u5f88\u6709\u7528\u7684\u529f\u80fd\u3002\u4e0b\u9762\u6211\u4ee5\u7ed8\u5236 badcase \u4e3a\u4f8b\uff1a # draw badcase with torch . no_grad (): output_argmax = output . detach () . permute ( 1 , 0 , 2 ) . argmax ( dim =- 1 ) loss = F . ctc_loss ( output_log_softmax , target , input_lengths , target_lengths , reduction = 'none' ) hard_sample = np . argsort ( loss . detach () . cpu () . numpy ())[:: - 1 ] data = data . cpu () target = target . cpu () nrow = 4 ncol = 4 fig = plt . figure ( figsize = ( 12 , 6 )) for i , index in enumerate ( hard_sample [: nrow * ncol ]): plt . subplot ( ncol , nrow , i + 1 ) plt . axis ( 'off' ) plt . imshow ( data [ index ] . numpy () . transpose ( 1 , 2 , 0 )) s = f 'true: { decode_target ( target [ index ]) } \\n pred: { decode ( output_argmax [ index ]) } ' plt . title ( s ) fig . canvas . draw () image = np . array ( fig . canvas . renderer . buffer_rgba ()) plt . close () writer . add_image ( 'train/badcase' , to_tensor ( image ), epoch ) \u9996\u5148\u4e3a\u4e86\u907f\u514d\u5f71\u54cd\u8bad\u7ec3\uff0c\u6574\u4e2a\u4ee3\u7801\u90fd\u9700\u8981\u5728 torch.no_grad() \u4e0b\u8fdb\u884c\u3002\u7136\u540e\u4e3a\u4e86\u83b7\u53d6\u4e0d\u597d\u8bc6\u522b\u7684\u6837\u672c\uff0c\u9700\u8981\u91cd\u65b0\u8ba1\u7b97 loss\uff0c\u5e76\u4e14\u6dfb\u52a0 reduction='none' \u4ee5\u8ba1\u7b97\u6bcf\u4e2a\u6837\u672c\u7684 loss\u3002 OCR \u95ee\u9898\u65e2\u9700\u8981\u56fe\u50cf\uff0c\u53c8\u9700\u8981\u6587\u672c\uff0c\u6240\u4ee5\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528 matplotlib \u7ed8\u5236\u56fe\u50cf\uff0c\u7136\u540e\u5f97\u5230\u77e9\u9635\u6bd4\u8f83\u65b9\u4fbf\u3002\u5982\u679c\u4f60\u53ea\u60f3\u62fc\u63a5\u591a\u4e2a\u56fe\u50cf\uff0c\u53ef\u4ee5\u4f7f\u7528 from torchvision.utils import make_grid \u51fd\u6570\u3002 \u4e0b\u9762\u662f\u8bad\u7ec3\u8fc7\u7a0b\u4e2d\u7684 badcase\uff1a \u53ef\u4ee5\u770b\u5230\u5927\u90e8\u5206\u56fe\u50cf\u90fd\u662f\u56e0\u4e3a 0 \u548c O \u8bc6\u522b\u4e0d\u5bf9\uff0c\u5176\u5b9e\u524d\u9762\u51e0\u4e2a\u56fe\u6211\u4e5f\u770b\u4e0d\u51fa\u6765\u5230\u5e95\u662f 0 \u8fd8\u662f O\u3002","title":"\u8bb0\u5f55\u56fe\u50cf\uff08images\uff09"},{"location":"how-to-use-tensorboard/#_4","text":"\u4ee5\u4e0a\u51e0\u4e2a\u4f8b\u5b50\u7684\u5b8c\u6574\u4ee3\u7801\u5728 https://github.com/ypwhs/captcha_break \u9879\u76ee\u4e2d\uff0c\u6587\u4ef6\u540d\u662f ctc_pytorch_tensorboard.ipynb \uff0c\u8be5\u9879\u76ee\u89e3\u51b3\u4e86\u9a8c\u8bc1\u7801\u8bc6\u522b\u7684\u95ee\u9898\uff0c\u6700\u7ec8\u8bad\u7ec3\u5230\u4e86 0.9957 \u7684\u51c6\u786e\u7387\u3002","title":"\u5b8c\u6574\u4ee3\u7801"},{"location":"how-to-use-tensorboard/#_5","text":"\u4f7f\u7528 TensorBoard \u53ef\u4ee5\u76d1\u63a7\u8bad\u7ec3\u8fc7\u7a0b\u4e2d\u7684 loss \u8d8b\u52bf\uff0c\u53ca\u65e9\u53d1\u73b0\u95ee\u9898\u3002\u8bad\u7ec3\u591a\u4e2a\u6a21\u578b\u4ee5\u540e\uff0c\u8fd8\u53ef\u4ee5\u628a\u591a\u4e2a\u6a21\u578b\u7684\u66f2\u7ebf\u653e\u5728\u4e00\u5f20\u56fe\u91cc\u6a2a\u5411\u5bf9\u6bd4\u3002\u53e6\u5916 badcase \u5206\u6790\u4e5f\u53ef\u4ee5\u53d1\u73b0\u66f4\u591a\u6f5c\u5728\u7684\u95ee\u9898\uff0c\u4e3a\u4e4b\u540e\u7684\u4f18\u5316\u5bfb\u627e\u65b9\u5411\u3002\u53ef\u4ee5\u8bf4 TensorBoard \u662f\u6bcf\u4e00\u4e2a\u6df1\u5ea6\u5b66\u4e60\u4ece\u4e1a\u8005\u7684\u5fc5\u5907\u6280\u80fd\u3002","title":"\u603b\u7ed3"},{"location":"linux-command/","text":"\u5e38\u7528 Linux \u547d\u4ee4 \u8fd9\u91cc\u4ecb\u7ecd\u4e86\u6700\u5e38\u7528\u7684 Linux \u547d\u4ee4\uff0c\u6709\u4e00\u4e9b\u5728\u5de5\u4f5c\u4e2d\u662f\u4e0d\u53ef\u6216\u7f3a\u7684\uff0c\u8fd8\u6709\u4e00\u4e9b\u80fd\u591f\u6781\u5927\u7684\u63d0\u9ad8\u6548\u7387\u3002\u60f3\u8981\u719f\u7ec3\u5730\u4f7f\u7528\u591a\u52a0\u7ec3\u4e60\u5373\u53ef\uff01 man Linux \u4e0b\u7684\u5e2e\u52a9\u547d\u4ee4\u3002 \u6388\u4eba\u4ee5\u9c7c\u4e0d\u5982\u6388\u4eba\u4ee5\u6e14\uff0c\u9996\u5148\u5e94\u8be5\u6559\u4f1a\u5927\u5bb6\u67e5\u6587\u6863\uff0c\u800c\u4e0d\u662f\u6559\u4f1a\u5927\u5bb6\u6240\u6709\u547d\u4ee4\u7684\u7528\u6cd5\u3002 \u5982\uff1a man ls \u53ef\u4ee5\u67e5\u770b ls \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u6863\u3002 \u63d0\u793a\uff1a\u6309 q \u9000\u51fa\u5e2e\u52a9\u9875\u9762\u3002 \u6587\u4ef6\u67e5\u770b cd \u5207\u6362\u5de5\u4f5c\u76ee\u5f55\u3002 ~ \u662f home directory \u7684\u610f\u601d\uff0c . \u8868\u793a\u76ee\u524d\u6240\u5728\u7684\u76ee\u5f55\uff0c .. \u8868\u793a\u76ee\u524d\u76ee\u5f55\u4f4d\u7f6e\u7684\u4e0a\u4e00\u5c42\u76ee\u5f55\u3002 cd .. \u8fd4\u56de\u4e0a\u4e00\u5c42\u76ee\u5f55\u3002 ls ls \u662f list \u7684\u7f29\u5199\uff0c\u7528\u6765\u663e\u793a\u76ee\u6807\u5217\u8868\u3002 ll \u662f ls -lh \u7684\u522b\u540d\uff0c\u5217\u51fa\u7684\u4fe1\u606f\u66f4\u52a0\u8be6\u7ec6\u3002 pwd pwd \u547d\u4ee4\u4ee5\u7edd\u5bf9\u8def\u5f84\u7684\u65b9\u5f0f\u663e\u793a\u7528\u6237\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 cat \u663e\u793a\u6587\u4ef6\u7684\u5185\u5bb9\uff1a cat file \u5f53\u6587\u4ef6\u8f83\u5927\u65f6\uff0c\u6587\u672c\u4f1a\u5728\u5c4f\u5e55\u4e0a\u5feb\u901f\u6eda\u52a8\uff0c\u53ef\u4ee5\u4f7f\u7528 Ctrl+S \u505c\u6b62\u6eda\u52a8\uff0c Ctrl+Q \u6062\u590d\u6eda\u52a8\uff0c Ctrl+C \u9000\u51fa\u5f53\u524d\u547d\u4ee4\u3002 head \u663e\u793a\u6587\u4ef6\u5f00\u5934\u7684\u5185\u5bb9\uff0c\u6bd4\u5982\uff1a head -n 5 train.csv \u53ef\u4ee5\u663e\u793a\u8bad\u7ec3\u96c6 csv \u524d\u4e94\u884c\u5185\u5bb9\u3002 tail \u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u7684\u5185\u5bb9\u3002 tail \u548c head \u9ed8\u8ba4\u663e\u793a 10 \u884c\u3002 find \u5728\u6307\u5b9a\u76ee\u5f55\u4e0b\u67e5\u627e\u6587\u4ef6\u3002 grep \u7b5b\u9009\u547d\u4ee4\uff0c\u6bd4\u5982\u6211\u60f3\u67e5\u627e\u8bb8\u591a\u6587\u4ef6\u91cc\u9762\u7684 markdown \u6587\u4ef6\uff1a ls -lh | grep .md \u279c pytorch git:(ff608a9) \u2717 ls -lh | grep .md -rw-rw-r-- 1 ypw ypw 15K 12\u6708 5 2018 CONTRIBUTING.md -rw-rw-r-- 1 ypw ypw 285 12\u6708 4 2018 mypy-README.md -rw-rw-r-- 1 ypw ypw 14K 12\u6708 5 2018 README.md whereis \u53ef\u4ee5\u67e5\u627e\u5305\u542b\u6307\u5b9a\u5173\u952e\u5b57\u7684\u6587\u4ef6\uff0c\u5982 whereis python \u53ef\u4ee5\u67e5\u627e\u6240\u6709\u7684\u6587\u4ef6\u540d\u5305\u542b python \u7684\u6587\u4ef6\u8def\u5f84\uff1a \u279c ~ whereis python python: /usr/bin/python2.7 /usr/bin/python3.5 /usr/bin/python /usr/bin/python3.5m /usr/lib/python2.7 /usr/lib/python3.5 /etc/python2.7 /etc/python3.5 /etc/python /usr/local/lib/python2.7 /usr/local/lib/python3.5 /usr/include/python3.5m /usr/share/python /home/ypw/anaconda3/bin/python3.6 /home/ypw/anaconda3/bin/python3.6m-config /home/ypw/anaconda3/bin/python3.6-config /home/ypw/anaconda3/bin/python3.6m /home/ypw/anaconda3/bin/python /usr/share/man/man1/python.1.gz which \u53ef\u4ee5\u67e5\u627e\u5f53\u524d\u4f7f\u7528\u7684\u547d\u4ee4\u7684\u7edd\u5bf9\u8def\u5f84\u3002 \u5982 which python \u53ef\u4ee5\u663e\u793a /home/ypw/anaconda3/bin/python \u3002 \u4f46\u662f\u5f53\u4f60\u6fc0\u6d3b\u4e00\u4e2a\u65b0\u7684\u73af\u5883\u4ee5\u540e\uff0c\u5c31\u4f1a\u5f97\u5230\u4e0d\u4e00\u6837\u7684\u7ed3\u679c\uff1a \u279c ~ source activate tensorflow ( tensorflow ) \u279c ~ which python /home/ypw/anaconda3/envs/tensorflow/bin/python locate locate \u547d\u4ee4\u4f1a\u5bfb\u627e\u5305\u542b\u5173\u952e\u5b57\u7684\u6240\u6709\u6587\u4ef6\u8def\u5f84\u3002 \u6587\u4ef6\u8bfb\u5199 mkdir \u521b\u5efa\u6587\u4ef6\u5939\u3002 touch \u521b\u5efa\u7a7a\u6587\u4ef6\u3002 rm \u79fb\u9664\u6587\u4ef6\u3002\u79fb\u9664\u6587\u4ef6\u5939\u65f6\u9700\u8981\u4f7f\u7528 rm -r \uff0c\u6ca1\u6709\u6743\u9650\u65f6\u9700\u8981 rm -rf \u3002 \u6b64\u547d\u4ee4\u6bd4\u8f83\u5371\u9669\uff0c\u6ce8\u610f\u4e0d\u8981\u5199\u6210\u8fd9\u6837\uff1a rm -rf / tmp \uff0c\u8fd9\u6837\u4f1a\u5220\u9664 / \u4e0b\u7684\u6240\u6709\u6587\u4ef6\uff0c\u5c5e\u4e8e\u5220\u5e93\u8dd1\u8def\u884c\u4e3a\u3002 cp \u590d\u5236\u6587\u4ef6\uff1a cp src dst \u590d\u5236\u6587\u4ef6\u5939\uff1a cp -r src dst mv \u79fb\u52a8\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a mv source destination vim \u7f16\u8f91\u6587\u4ef6\u7684\u547d\u4ee4\uff0c\u5b66\u4e60\u66f2\u7ebf\u6bd4\u8f83\u9661\u5ced\uff0c\u5efa\u8bae\u641c\u7d22\u76f8\u5173\u6559\u7a0b\u5b66\u4e60\u3002 nano Ubuntu \u81ea\u5e26\u7684\u7f16\u8f91\u6587\u4ef6\u7684\u547d\u4ee4\u3002 \u4f7f\u7528\u65b9\u6cd5\uff1a nano ~/.ssh/authorized_keys \u63d0\u793a\uff1a Ctrl+O \u53ef\u4ee5\u4fdd\u5b58\u6587\u4ef6\uff0c Ctrl+K \u53ef\u4ee5\u5220\u9664\u6574\u884c\uff0c Ctrl+W \u53ef\u4ee5\u67e5\u627e\u6587\u672c\uff0c Ctrl+X \u53ef\u4ee5\u9000\u51fa\u7f16\u8f91\u5668\uff0c\u5176\u4ed6\u7279\u6027\u53ef\u4ee5\u6839\u636e\u5e95\u90e8\u7684\u5feb\u6377\u952e\u81ea\u884c\u5b66\u4e60\u3002 \u6253\u5305\u538b\u7f29 zip \u538b\u7f29\u547d\u4ee4\uff0c\u901a\u8fc7 zip file.zip file \u53ef\u4ee5\u538b\u7f29\u4e00\u4e2a\u6587\u4ef6\uff0c\u901a\u8fc7 zip files.zip -r dir \u53ef\u4ee5\u538b\u7f29\u6574\u4e2a\u6587\u4ef6\u5939\u3002 unzip \u89e3\u538b\u7531 zip \u547d\u4ee4\u538b\u7f29\u7684 .zip \u6587\u4ef6\u3002 \u4f8b\u5982\uff1a unzip files.zip tar *.tar \u6253\u5305\u6587\u4ef6\uff1a\u53ea\u662f\u628a\u5f88\u591a\u5c0f\u6587\u4ef6\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u901f\u5ea6\u5feb\uff0c\u4e0d\u5360\u7528 CPU\uff0c\u6bd4\u5982 ImageNet \u6570\u636e\u96c6\u5c31\u662f\u4e00\u4e2a\u6253\u5305\u6587\u4ef6\uff0c\u89e3\u5305\u7684\u901f\u5ea6\u975e\u5e38\u5feb\u3002\u6253\u5305\u540e\u7684\u6587\u4ef6\u5927\u5c0f\u548c\u539f\u59cb\u6587\u4ef6\u5939\u7684\u5927\u5c0f\u57fa\u672c\u4e00\u81f4\u3002 *.tar.gz \u538b\u7f29\u6587\u4ef6\uff1a\u5148\u6253\u5305\u6210\u4e00\u4e2a\u6587\u4ef6\uff0c\u7136\u540e\u518d\u538b\u7f29\u4e00\u904d\uff0c\u5c31\u662f\u8fd9\u4e2a\u683c\u5f0f\u3002\u5982\u679c\u6587\u4ef6\u662f\u672a\u538b\u7f29\u7684\u683c\u5f0f\uff0c\u6bd4\u5982\u6587\u672c\u6587\u4ef6\uff0c\u4f7f\u7528\u8fd9\u4e2a\u683c\u5f0f\u53ef\u4ee5\u6709\u5f88\u9ad8\u7684\u538b\u7f29\u6bd4\u3002\u6ce8\u610f\uff1ajpg \u548c png \u683c\u5f0f\u662f\u538b\u7f29\u540e\u7684\u683c\u5f0f\uff0c\u53ea\u6253\u5305\u5c31\u884c\uff0c\u5982\u679c\u5bf9 ImageNet \u6570\u636e\u96c6\u5148\u6253\u5305\u518d\u538b\u7f29\uff0c\u5c31\u4f1a\u6709\u5f88\u957f\u7684\u8017\u65f6\uff0c\u5e76\u4e14\u6587\u4ef6\u4e0d\u4f1a\u660e\u663e\u53d8\u5c0f\u3002 c\uff1a\u6253\u5305 x\uff1a\u89e3\u5305 v\uff1a\u8f93\u51fa\u8be6\u7ec6\u4fe1\u606f f\uff1a\u6307\u5b9a\u6253\u5305\u6587\u4ef6 z\uff1a\u4f7f\u7528 gzip \u538b\u7f29\u683c\u5f0f \u6253\u5305\u6587\u4ef6\u5939\uff1a tar -cvf files.tar dir \u89e3\u5305\uff1a tar -xvf files.tar \u538b\u7f29\u6587\u4ef6\u5939\uff1a tar -czvf files.tar.gz dir \u89e3\u538b\uff1a tar -xzvf files.tar.gz \u6743\u9650\u7ba1\u7406 sudo \u4ee5 root \u6743\u9650\u6267\u884c\u547d\u4ee4\uff0c\u6bd4\u5982 sudo reboot \u53ef\u4ee5\u91cd\u542f\u673a\u5668\uff0c\u666e\u901a\u6743\u9650\u65e0\u6cd5\u91cd\u542f\u3002 su \u5207\u6362\u7528\u6237\uff0c\u6bd4\u5982 sudo su ypw \u53ef\u4ee5\u5c06\u5f53\u524d\u7528\u6237\u5207\u6362\u5230 ypw \u7528\u6237\u3002 chmod \u4fee\u6539\u6743\u9650\u7684\u547d\u4ee4\uff0c\u6bd4\u5982\uff1a sudo chmod -R 777 data \u53ef\u4ee5\u628a data \u6587\u4ef6\u5939\u4fee\u6539\u4e3a\u4efb\u4f55\u4eba\u53ef\u4ee5\u8bfb\u5199\u3002 chown \u4fee\u6539\u6240\u6709\u8005\u7684\u547d\u4ee4\uff0c\u6bd4\u5982\uff1a sudo chown -R ypw data \u53ef\u4ee5\u628a data \u6587\u4ef6\u5939\u7684\u6240\u6709\u6743\u6539\u4e3a ypw\u3002 passwd \u4fee\u6539\u5bc6\u7801\u547d\u4ee4\uff0c\u76f4\u63a5\u6267\u884c passwd \u53ef\u4ee5\u4fee\u6539\u5f53\u524d\u7528\u6237\u5bc6\u7801\u3002 \u5f3a\u5236\u4fee\u6539\u67d0\u4e2a\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd ypw \u8fdb\u7a0b\u7ba1\u7406 ps ps aux \u53ef\u4ee5\u5217\u51fa\u6240\u6709\u8fdb\u7a0b\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 \u914d\u5408 grep \u547d\u4ee4\u7528\u6bd4\u8f83\u597d\uff0c\u6bd4\u5982 ps aux | grep ipython | grep -v grep \u9996\u5148\u4f7f\u7528 ps aux \u83b7\u53d6\u6240\u6709\u7684\u8fdb\u7a0b\u4fe1\u606f\uff0c\u7136\u540e\u7528 grep ipython \u67e5\u627e\u5e26\u6709 python \u7684\u8fdb\u7a0b\uff0c\u6700\u540e\u4f7f\u7528 grep -v grep \u8fc7\u6ee4 grep \u8fdb\u7a0b\u672c\u8eab\u3002 kill \u6740\u6389\u6267\u884c\u4e2d\u7684\u8fdb\u7a0b\uff0c\u521a\u624d ps \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u8fdb\u7a0b\u53f7\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u8fdb\u7a0b\u53f7\u5220\u9664\u8be5\u8fdb\u7a0b\uff0c\u5982 kill 8339 killall \u901a\u8fc7\u8fdb\u7a0b\u540d\u6765\u6740\u6389\u8fdb\u7a0b\uff0c\u8bf7\u786e\u4fdd\u4f60\u4e0d\u4f1a\u5f71\u54cd\u5176\u4ed6\u4eba\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528\u8be5\u547d\u4ee4\u3002 \u5982\u679c\u540c\u4e8b\u6b63\u5728\u4f7f\u7528 python \u8dd1\u7a0b\u5e8f\uff0c\u4f60\u4e5f\u5728\u4f7f\u7528 python \u8dd1\u7a0b\u5e8f\uff0c\u5728\u4f60\u6267\u884c\u5b8c killall python \u4ee5\u540e\uff0c\u4f60\u4eec\u7684 python \u8fdb\u7a0b\u90fd\u4f1a\u88ab\u6740\u6389\u3002 \u78c1\u76d8\u7ba1\u7406 df \u67e5\u770b\u78c1\u76d8\u7a7a\u95f4\uff0c\u6bd4\u5982 df -h \u53ef\u4ee5\u663e\u793a\u4e0b\u9762\u7684\u5185\u5bb9\uff1a Filesystem Size Used Avail Use% Mounted on udev 32G 0 32G 0% /dev tmpfs 6.3G 9.5M 6.3G 1% /run /dev/nvme0n1p2 916G 248G 622G 29% / tmpfs 32G 679M 31G 3% /dev/shm tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 32G 0 32G 0% /sys/fs/cgroup /dev/nvme0n1p1 511M 3.5M 508M 1% /boot/efi tmpfs 6.3G 32K 6.3G 1% /run/user/1000 \u4f7f\u7528 df -ih \u53ef\u4ee5\u67e5\u770b Inodes \u4f7f\u7528\u60c5\u51b5\uff0c\u5982\u679c\u4f60\u7684\u78c1\u76d8\u4e0b\u5b58\u5728\u5f88\u591a\u5c0f\u6587\u4ef6\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\u67e5\u770b\u6587\u4ef6\u8868\u662f\u5426\u7528\u5b8c\u4e86\u3002 du \u53ef\u4ee5\u67e5\u770b\u6587\u4ef6\u5939\u5927\u5c0f\uff0c\u6bd4\u5982\uff1a du -h ImageNet \u53ef\u4ee5\u8f93\u51fa\u4e0b\u9762\u7684\u5185\u5bb9\uff1a ...... 163M ImageNet/train/n12620546 128M ImageNet/train/n02108551 127M ImageNet/train/n15075141 140G ImageNet/train 6.4G ImageNet/val 146G ImageNet mount \u6302\u8f7d\u78c1\u76d8\u7684\u547d\u4ee4\uff0c\u6302\u8f7d\u786c\u76d8\uff1a sudo mount -t ext4 /dev/nvme0n1p1 /data \u6302\u8f7d samba \u7f51\u7edc\u76d8\uff1a sudo mount -t cifs -o username = ypw,password = **** //192.168.8.57/dataset /home/ypw/dataset \u6ce8\u610f\uff1a\u6b64\u5904\u9700\u8981 sudo apt install cifs-utils \u3002 \u7cfb\u7edf\u7ba1\u7406 apt Ubuntu \u7cfb\u7edf\u7684\u5305\u7ba1\u7406\u5668\uff0c\u7528\u4e8e\u5b89\u88c5\u548c\u5378\u8f7d\u8f6f\u4ef6\u5305\u3002 \u5b89\u88c5\uff1a sudo apt install curl \u5378\u8f7d\uff1a sudo apt purge curl export \u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u547d\u4ee4\uff0c\u4e00\u822c\u5199\u5728 .bashrc \u6216 .zshrc \u6587\u4ef6\u4e2d\uff0c\u4f8b\u5982\uff1a export PATH = /usr/local/cuda/bin: $PATH \u7684\u529f\u80fd\u662f\u628a /usr/local/cuda/bin \u76ee\u5f55\u6dfb\u52a0\u5230 PATH \u7684\u6700\u524d\u9762\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u76f4\u63a5\u5728\u547d\u4ee4\u884c\u4f7f\u7528 /usr/local/cuda/bin \u76ee\u5f55\u4e0b\u7684 nvcc \u547d\u4ee4\u3002 source \u66f4\u65b0\u73af\u5883\u53d8\u91cf\u3002 \u5982 zsh \u7528\u6237\u66f4\u65b0\u4e86 ~/.zshrc \u4ee5\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u66f4\u65b0\u73af\u5883\u53d8\u91cf\uff1a source ~/.zshrc update-alternatives \u5207\u6362\u547d\u4ee4\u7248\u672c\u3002\u6bd4\u5982\u4f60\u88c5\u4e86\u5f88\u591a\u4e2a CUDA \u7248\u672c\uff1a sudo update - alternatives -- config cuda There are 3 choices for the alternative cuda ( providing / usr / local / cuda ) . Selection Path Priority Status ------------------------------------------------------------ 0 / usr / local / cuda - 12 . 1 121 auto mode 1 / usr / local / cuda - 11 . 3 113 manual mode * 2 / usr / local / cuda - 11 . 7 117 manual mode 3 / usr / local / cuda - 12 . 1 121 manual mode Press < enter > to keep the current choice [ * ], or type selection number : \u4f60\u5c31\u53ef\u4ee5\u4f7f\u7528 sudo update-alternatives --config cuda \u547d\u4ee4\u9009\u62e9\u4f60\u60f3\u7528\u7684\u7248\u672c\uff0c\u8f93\u5165\u6570\u5b57\uff0c\u7136\u540e\u56de\u8f66\uff0c\u5c31\u53ef\u4ee5\u5207\u6362\u8fc7\u53bb\u3002 echo \u53ef\u4ee5\u8f93\u51fa\u73af\u5883\u53d8\u91cf\u3002 \u4f8b\u5982\uff1a echo $PATH service \u5f00\u542f\u5173\u95ed\u670d\u52a1\u7684\u547d\u4ee4\uff0c\u5982\uff1a sudo service network-manager restart shutdown \u5173\u673a\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a sudo shutdown -t 0 reboot \u91cd\u542f\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a sudo reboot \u7cfb\u7edf\u76d1\u6d4b uname \u663e\u793a\u5f53\u524d\u7684\u7cfb\u7edf\u4fe1\u606f\u3002 uname -a \u663e\u793a\u5168\u90e8\u7684\u4fe1\u606f\uff0c\u5982\u5185\u6838\u7248\u672c\u53f7\u3001\u786c\u4ef6\u67b6\u6784\u3001\u4e3b\u673a\u540d\u79f0\u548c\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7b49\u3002 top \u5b9e\u65f6\u67e5\u770b\u7cfb\u7edf\u7684\u8fd0\u884c\u72b6\u6001\uff0c\u5982 CPU\u3001\u5185\u5b58\u3001\u8fdb\u7a0b\u7684\u4fe1\u606f\u3002 ifconfig \u8fd9\u4e2a\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u5f53\u524d\u7f51\u5361\u7684 ip \u5730\u5740\u3002\u5982\uff1a \u279c ~ ifconfig | grep inet inet addr:192.168.8.100 Bcast:192.168.8.255 Mask:255.255.255.0 inet6 addr: fe80::211d:78f6:888a:1/64 Scope:Link inet addr:127.0.0.1 Mask:255.0.0.0 free \u67e5\u770b\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff0c\u5982\uff1a free -h total used free shared buff/cache available Mem: 62G 404M 61G 9.4M 891M 61G Swap: 976M 0B 976M \u7f51\u7edc\u901a\u4fe1 ping \u6d4b\u8bd5\u4e3b\u673a\u4e4b\u95f4\u7f51\u7edc\u7684\u8fde\u901a\u6027\u3002 \u4f8b\u5982\uff1a ping baidu.com ssh \u8fde\u63a5\u8fdc\u7a0b\u670d\u52a1\u5668\uff1a ssh user@192.168.1.100 \u6620\u5c04\u8fdc\u7a0b\u7aef\u53e3\uff1a ssh -L \u672c\u5730\u7aef\u53e3:\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u7aef\u53e3 \u8fdc\u7a0b\u670d\u52a1\u5668 \u4f8b\u5982\uff1a ssh -L 8888:localhost:8888 192.168.1.100 \u53ef\u4ee5\u628a\u670d\u52a1\u5668\u4e0a\u7684 jupyter \u76d1\u542c\u7684 8888 \u7aef\u53e3\u6620\u5c04\u5230\u672c\u5730\u7684 8888 \u7aef\u53e3\uff0c\u7136\u540e\u53ea\u9700\u8981\u5728\u6d4f\u89c8\u5668\u91cc\u8f93\u5165 http://localhost:8888 \u5c31\u53ef\u4ee5\u8fde\u63a5\u8fdc\u7a0b\u670d\u52a1\u5668\u7684 jupyter \u4e86\u3002 scp \u590d\u5236\u6587\u4ef6/\u6587\u4ef6\u5939\u5230\u8fdc\u7a0b\u670d\u52a1\u5668\uff0c\u6216\u8005\u53cd\u5411\u590d\u5236\uff0c\u4f8b\u5982\uff1a \u4ece\u672c\u5730\u590d\u5236\u5230\u8fdc\u7a0b\uff1a scp \u672c\u5730\u6587\u4ef6 \u7528\u6237\u540d@\u76ee\u6807\u4e3b\u673a:\u76ee\u6807\u4e3b\u673a\u8def\u5f84 \u4ece\u8fdc\u7a0b\u590d\u5236\u5230\u672c\u5730\uff1a scp \u7528\u6237\u540d@\u76ee\u6807\u4e3b\u673a:\u76ee\u6807\u4e3b\u673a\u6587\u4ef6 \u672c\u5730\u5730\u5740 \u590d\u5236\u6587\u4ef6\uff1a scp filename user@192.168.1.100:/data \u590d\u5236\u6587\u4ef6\u5939\u9700\u8981\u6dfb\u52a0 -r \u53c2\u6570\uff1a scp -r directory user@192.168.1.100:/data \u5f53\u4f60\u590d\u5236\u5927\u91cf\u5c0f\u6587\u4ef6\u65f6\uff0c\u8bf7\u4f7f\u7528 rsync \u547d\u4ee4\u3002 rsync \u540c\u6b65\u6587\u4ef6/\u6587\u4ef6\u5939\u547d\u4ee4\uff0c\u5e26\u6709\u589e\u91cf\u5907\u4efd\u529f\u80fd\uff0c\u901f\u5ea6\u5f88\u5feb\u3002 \u53c2\u6570\uff1a -a\uff0c--archive \u5f52\u6863\u6a21\u5f0f\uff0c\u8868\u793a\u4ee5\u9012\u5f52\u65b9\u5f0f\u4f20\u8f93\u6587\u4ef6\uff0c\u5e76\u4fdd\u6301\u6240\u6709\u6587\u4ef6\u5c5e\u6027\uff0c\u7b49\u4e8e-rlptgoD\u3002 -v\uff0c--verbose \u8be6\u7ec6\u6a21\u5f0f\u8f93\u51fa\u3002 -z\uff0c--compress \u5728\u4f20\u8f93\u65f6\u538b\u7f29\u6570\u636e\uff0c\u5982\u679c\u4f60\u4f20\u8f93\u7684\u6587\u4ef6\u6ca1\u6709\u538b\u7f29\u8fc7\uff0c\u5e76\u4e14\u5e26\u5bbd\u4e0d\u591f\u5927\uff0c\u5c31\u53ef\u4ee5\u5f00\u542f\u538b\u7f29\u3002\u5982\u679c\u4f60\u4f20\u8f93\u7684\u662f\u56fe\u50cf\u6587\u4ef6\uff0c\u90a3\u4e48\u538b\u7f29\u4f1a\u62d6\u6162\u4f20\u8f93\u901f\u5ea6\u3002 --delete\uff0c\u5728\u540c\u6b65\u7684\u65f6\u5019\u5220\u9664\u591a\u4f59\u7684\u6587\u4ef6\uff0c\u8fd9\u53ef\u4ee5\u786e\u4fdd\u4e24\u4e2a\u6587\u4ef6\u5939\u7684\u4e00\u81f4\u6027\u3002 --exclude\uff0c\u6392\u9664\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26 -P\uff0c\u7b49\u540c\u4e8e --partial --progress\uff0c\u663e\u793a\u5907\u4efd\u8fc7\u7a0b\u3002 \u547d\u4ee4\uff1a rsync -avP \u6e90\u8def\u5f84 \u76ee\u7684\u5730\u8def\u5f84 \uff0c\u5176\u4e2d\u6e90\u8def\u5f84\u53ef\u4ee5\u662f\u672c\u5730\u6587\u4ef6\u5939\u8def\u5f84\uff0c\u4e5f\u53ef\u4ee5\u662f\u8fdc\u7a0b\u8def\u5f84\uff0c\u76ee\u7684\u5730\u8def\u5f84\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u548c\u8fdc\u7a0b\u8def\u5f84\u3002 \u5982\uff1a \u5c06\u672c\u5730\u7684\u6587\u4ef6\u5939\u540c\u6b65\u5230\u670d\u52a1\u5668\uff1a rsync -avP \u672c\u5730\u8def\u5f84 \u7528\u6237\u540d@\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u8def\u5f84 \u5c06\u670d\u52a1\u5668\u4e0a\u7684\u6587\u4ef6\u5939\u540c\u6b65\u5230\u672c\u5730\uff1a rsync -avP \u7528\u6237\u540d@\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u8def\u5f84 \u672c\u5730\u8def\u5f84 \u672c\u5730\u62f7\u8d1d\u6587\u4ef6\u5939\uff1a rsync -avP \u672c\u5730\u6e90\u8def\u5f84 \u672c\u5730\u76ee\u7684\u5730\u8def\u5f84 \u6ce8\u610f\uff1a \u5982\u679c\u540c\u6b65\u7684\u6e90\u8def\u5f84\u540e\u9762\u52a0\u4e86\u659c\u6760 / \uff0c\u5219\u540c\u6b65\u7684\u76ee\u7684\u5730\u4e0d\u4f1a\u521b\u5efa\u5b50\u6587\u4ef6\u5939\u3002\u6bd4\u5982\u5c06\u4e00\u53f0\u670d\u52a1\u5668\u4e0a\u7684 home \u76ee\u5f55\u540c\u6b65\u53e6\u4e00\u53f0\u670d\u52a1\u5668\uff1a rsync -avP \u914d\u597d\u7684\u670d\u52a1\u5668:/home/ypw/ . \u4e0b\u9762\u662f\u4e00\u4e2a\u628a\u8fdc\u7a0b\u670d\u52a1\u5668\u540c\u6b65\u5230\u672c\u5730\u7684\u4f8b\u5b50\uff1a wget \u4ece\u6307\u5b9a\u7684URL\u4e0b\u8f7d\u6587\u4ef6\u3002 \u4e0b\u8f7d\u5355\u4e2a\u6587\u4ef6\uff1a wget url \u4e0b\u8f7d\u5e76\u4fee\u6539\u6587\u4ef6\u540d\uff1a wget -O filename.zip url","title":"\u5e38\u7528 Linux \u547d\u4ee4"},{"location":"linux-command/#linux","text":"\u8fd9\u91cc\u4ecb\u7ecd\u4e86\u6700\u5e38\u7528\u7684 Linux \u547d\u4ee4\uff0c\u6709\u4e00\u4e9b\u5728\u5de5\u4f5c\u4e2d\u662f\u4e0d\u53ef\u6216\u7f3a\u7684\uff0c\u8fd8\u6709\u4e00\u4e9b\u80fd\u591f\u6781\u5927\u7684\u63d0\u9ad8\u6548\u7387\u3002\u60f3\u8981\u719f\u7ec3\u5730\u4f7f\u7528\u591a\u52a0\u7ec3\u4e60\u5373\u53ef\uff01","title":"\u5e38\u7528 Linux \u547d\u4ee4"},{"location":"linux-command/#man","text":"Linux \u4e0b\u7684\u5e2e\u52a9\u547d\u4ee4\u3002 \u6388\u4eba\u4ee5\u9c7c\u4e0d\u5982\u6388\u4eba\u4ee5\u6e14\uff0c\u9996\u5148\u5e94\u8be5\u6559\u4f1a\u5927\u5bb6\u67e5\u6587\u6863\uff0c\u800c\u4e0d\u662f\u6559\u4f1a\u5927\u5bb6\u6240\u6709\u547d\u4ee4\u7684\u7528\u6cd5\u3002 \u5982\uff1a man ls \u53ef\u4ee5\u67e5\u770b ls \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u6863\u3002 \u63d0\u793a\uff1a\u6309 q \u9000\u51fa\u5e2e\u52a9\u9875\u9762\u3002","title":"man"},{"location":"linux-command/#_1","text":"","title":"\u6587\u4ef6\u67e5\u770b"},{"location":"linux-command/#cd","text":"\u5207\u6362\u5de5\u4f5c\u76ee\u5f55\u3002 ~ \u662f home directory \u7684\u610f\u601d\uff0c . \u8868\u793a\u76ee\u524d\u6240\u5728\u7684\u76ee\u5f55\uff0c .. \u8868\u793a\u76ee\u524d\u76ee\u5f55\u4f4d\u7f6e\u7684\u4e0a\u4e00\u5c42\u76ee\u5f55\u3002 cd .. \u8fd4\u56de\u4e0a\u4e00\u5c42\u76ee\u5f55\u3002","title":"cd"},{"location":"linux-command/#ls","text":"ls \u662f list \u7684\u7f29\u5199\uff0c\u7528\u6765\u663e\u793a\u76ee\u6807\u5217\u8868\u3002 ll \u662f ls -lh \u7684\u522b\u540d\uff0c\u5217\u51fa\u7684\u4fe1\u606f\u66f4\u52a0\u8be6\u7ec6\u3002","title":"ls"},{"location":"linux-command/#pwd","text":"pwd \u547d\u4ee4\u4ee5\u7edd\u5bf9\u8def\u5f84\u7684\u65b9\u5f0f\u663e\u793a\u7528\u6237\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002","title":"pwd"},{"location":"linux-command/#cat","text":"\u663e\u793a\u6587\u4ef6\u7684\u5185\u5bb9\uff1a cat file \u5f53\u6587\u4ef6\u8f83\u5927\u65f6\uff0c\u6587\u672c\u4f1a\u5728\u5c4f\u5e55\u4e0a\u5feb\u901f\u6eda\u52a8\uff0c\u53ef\u4ee5\u4f7f\u7528 Ctrl+S \u505c\u6b62\u6eda\u52a8\uff0c Ctrl+Q \u6062\u590d\u6eda\u52a8\uff0c Ctrl+C \u9000\u51fa\u5f53\u524d\u547d\u4ee4\u3002","title":"cat"},{"location":"linux-command/#head","text":"\u663e\u793a\u6587\u4ef6\u5f00\u5934\u7684\u5185\u5bb9\uff0c\u6bd4\u5982\uff1a head -n 5 train.csv \u53ef\u4ee5\u663e\u793a\u8bad\u7ec3\u96c6 csv \u524d\u4e94\u884c\u5185\u5bb9\u3002","title":"head"},{"location":"linux-command/#tail","text":"\u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u7684\u5185\u5bb9\u3002 tail \u548c head \u9ed8\u8ba4\u663e\u793a 10 \u884c\u3002","title":"tail"},{"location":"linux-command/#find","text":"\u5728\u6307\u5b9a\u76ee\u5f55\u4e0b\u67e5\u627e\u6587\u4ef6\u3002","title":"find"},{"location":"linux-command/#grep","text":"\u7b5b\u9009\u547d\u4ee4\uff0c\u6bd4\u5982\u6211\u60f3\u67e5\u627e\u8bb8\u591a\u6587\u4ef6\u91cc\u9762\u7684 markdown \u6587\u4ef6\uff1a ls -lh | grep .md \u279c pytorch git:(ff608a9) \u2717 ls -lh | grep .md -rw-rw-r-- 1 ypw ypw 15K 12\u6708 5 2018 CONTRIBUTING.md -rw-rw-r-- 1 ypw ypw 285 12\u6708 4 2018 mypy-README.md -rw-rw-r-- 1 ypw ypw 14K 12\u6708 5 2018 README.md","title":"grep"},{"location":"linux-command/#whereis","text":"\u53ef\u4ee5\u67e5\u627e\u5305\u542b\u6307\u5b9a\u5173\u952e\u5b57\u7684\u6587\u4ef6\uff0c\u5982 whereis python \u53ef\u4ee5\u67e5\u627e\u6240\u6709\u7684\u6587\u4ef6\u540d\u5305\u542b python \u7684\u6587\u4ef6\u8def\u5f84\uff1a \u279c ~ whereis python python: /usr/bin/python2.7 /usr/bin/python3.5 /usr/bin/python /usr/bin/python3.5m /usr/lib/python2.7 /usr/lib/python3.5 /etc/python2.7 /etc/python3.5 /etc/python /usr/local/lib/python2.7 /usr/local/lib/python3.5 /usr/include/python3.5m /usr/share/python /home/ypw/anaconda3/bin/python3.6 /home/ypw/anaconda3/bin/python3.6m-config /home/ypw/anaconda3/bin/python3.6-config /home/ypw/anaconda3/bin/python3.6m /home/ypw/anaconda3/bin/python /usr/share/man/man1/python.1.gz","title":"whereis"},{"location":"linux-command/#which","text":"\u53ef\u4ee5\u67e5\u627e\u5f53\u524d\u4f7f\u7528\u7684\u547d\u4ee4\u7684\u7edd\u5bf9\u8def\u5f84\u3002 \u5982 which python \u53ef\u4ee5\u663e\u793a /home/ypw/anaconda3/bin/python \u3002 \u4f46\u662f\u5f53\u4f60\u6fc0\u6d3b\u4e00\u4e2a\u65b0\u7684\u73af\u5883\u4ee5\u540e\uff0c\u5c31\u4f1a\u5f97\u5230\u4e0d\u4e00\u6837\u7684\u7ed3\u679c\uff1a \u279c ~ source activate tensorflow ( tensorflow ) \u279c ~ which python /home/ypw/anaconda3/envs/tensorflow/bin/python","title":"which"},{"location":"linux-command/#locate","text":"locate \u547d\u4ee4\u4f1a\u5bfb\u627e\u5305\u542b\u5173\u952e\u5b57\u7684\u6240\u6709\u6587\u4ef6\u8def\u5f84\u3002","title":"locate"},{"location":"linux-command/#_2","text":"","title":"\u6587\u4ef6\u8bfb\u5199"},{"location":"linux-command/#mkdir","text":"\u521b\u5efa\u6587\u4ef6\u5939\u3002","title":"mkdir"},{"location":"linux-command/#touch","text":"\u521b\u5efa\u7a7a\u6587\u4ef6\u3002","title":"touch"},{"location":"linux-command/#rm","text":"\u79fb\u9664\u6587\u4ef6\u3002\u79fb\u9664\u6587\u4ef6\u5939\u65f6\u9700\u8981\u4f7f\u7528 rm -r \uff0c\u6ca1\u6709\u6743\u9650\u65f6\u9700\u8981 rm -rf \u3002 \u6b64\u547d\u4ee4\u6bd4\u8f83\u5371\u9669\uff0c\u6ce8\u610f\u4e0d\u8981\u5199\u6210\u8fd9\u6837\uff1a rm -rf / tmp \uff0c\u8fd9\u6837\u4f1a\u5220\u9664 / \u4e0b\u7684\u6240\u6709\u6587\u4ef6\uff0c\u5c5e\u4e8e\u5220\u5e93\u8dd1\u8def\u884c\u4e3a\u3002","title":"rm"},{"location":"linux-command/#cp","text":"\u590d\u5236\u6587\u4ef6\uff1a cp src dst \u590d\u5236\u6587\u4ef6\u5939\uff1a cp -r src dst","title":"cp"},{"location":"linux-command/#mv","text":"\u79fb\u52a8\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a mv source destination","title":"mv"},{"location":"linux-command/#vim","text":"\u7f16\u8f91\u6587\u4ef6\u7684\u547d\u4ee4\uff0c\u5b66\u4e60\u66f2\u7ebf\u6bd4\u8f83\u9661\u5ced\uff0c\u5efa\u8bae\u641c\u7d22\u76f8\u5173\u6559\u7a0b\u5b66\u4e60\u3002","title":"vim"},{"location":"linux-command/#nano","text":"Ubuntu \u81ea\u5e26\u7684\u7f16\u8f91\u6587\u4ef6\u7684\u547d\u4ee4\u3002 \u4f7f\u7528\u65b9\u6cd5\uff1a nano ~/.ssh/authorized_keys \u63d0\u793a\uff1a Ctrl+O \u53ef\u4ee5\u4fdd\u5b58\u6587\u4ef6\uff0c Ctrl+K \u53ef\u4ee5\u5220\u9664\u6574\u884c\uff0c Ctrl+W \u53ef\u4ee5\u67e5\u627e\u6587\u672c\uff0c Ctrl+X \u53ef\u4ee5\u9000\u51fa\u7f16\u8f91\u5668\uff0c\u5176\u4ed6\u7279\u6027\u53ef\u4ee5\u6839\u636e\u5e95\u90e8\u7684\u5feb\u6377\u952e\u81ea\u884c\u5b66\u4e60\u3002","title":"nano"},{"location":"linux-command/#_3","text":"","title":"\u6253\u5305\u538b\u7f29"},{"location":"linux-command/#zip","text":"\u538b\u7f29\u547d\u4ee4\uff0c\u901a\u8fc7 zip file.zip file \u53ef\u4ee5\u538b\u7f29\u4e00\u4e2a\u6587\u4ef6\uff0c\u901a\u8fc7 zip files.zip -r dir \u53ef\u4ee5\u538b\u7f29\u6574\u4e2a\u6587\u4ef6\u5939\u3002","title":"zip"},{"location":"linux-command/#unzip","text":"\u89e3\u538b\u7531 zip \u547d\u4ee4\u538b\u7f29\u7684 .zip \u6587\u4ef6\u3002 \u4f8b\u5982\uff1a unzip files.zip","title":"unzip"},{"location":"linux-command/#tar","text":"*.tar \u6253\u5305\u6587\u4ef6\uff1a\u53ea\u662f\u628a\u5f88\u591a\u5c0f\u6587\u4ef6\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u901f\u5ea6\u5feb\uff0c\u4e0d\u5360\u7528 CPU\uff0c\u6bd4\u5982 ImageNet \u6570\u636e\u96c6\u5c31\u662f\u4e00\u4e2a\u6253\u5305\u6587\u4ef6\uff0c\u89e3\u5305\u7684\u901f\u5ea6\u975e\u5e38\u5feb\u3002\u6253\u5305\u540e\u7684\u6587\u4ef6\u5927\u5c0f\u548c\u539f\u59cb\u6587\u4ef6\u5939\u7684\u5927\u5c0f\u57fa\u672c\u4e00\u81f4\u3002 *.tar.gz \u538b\u7f29\u6587\u4ef6\uff1a\u5148\u6253\u5305\u6210\u4e00\u4e2a\u6587\u4ef6\uff0c\u7136\u540e\u518d\u538b\u7f29\u4e00\u904d\uff0c\u5c31\u662f\u8fd9\u4e2a\u683c\u5f0f\u3002\u5982\u679c\u6587\u4ef6\u662f\u672a\u538b\u7f29\u7684\u683c\u5f0f\uff0c\u6bd4\u5982\u6587\u672c\u6587\u4ef6\uff0c\u4f7f\u7528\u8fd9\u4e2a\u683c\u5f0f\u53ef\u4ee5\u6709\u5f88\u9ad8\u7684\u538b\u7f29\u6bd4\u3002\u6ce8\u610f\uff1ajpg \u548c png \u683c\u5f0f\u662f\u538b\u7f29\u540e\u7684\u683c\u5f0f\uff0c\u53ea\u6253\u5305\u5c31\u884c\uff0c\u5982\u679c\u5bf9 ImageNet \u6570\u636e\u96c6\u5148\u6253\u5305\u518d\u538b\u7f29\uff0c\u5c31\u4f1a\u6709\u5f88\u957f\u7684\u8017\u65f6\uff0c\u5e76\u4e14\u6587\u4ef6\u4e0d\u4f1a\u660e\u663e\u53d8\u5c0f\u3002 c\uff1a\u6253\u5305 x\uff1a\u89e3\u5305 v\uff1a\u8f93\u51fa\u8be6\u7ec6\u4fe1\u606f f\uff1a\u6307\u5b9a\u6253\u5305\u6587\u4ef6 z\uff1a\u4f7f\u7528 gzip \u538b\u7f29\u683c\u5f0f \u6253\u5305\u6587\u4ef6\u5939\uff1a tar -cvf files.tar dir \u89e3\u5305\uff1a tar -xvf files.tar \u538b\u7f29\u6587\u4ef6\u5939\uff1a tar -czvf files.tar.gz dir \u89e3\u538b\uff1a tar -xzvf files.tar.gz","title":"tar"},{"location":"linux-command/#_4","text":"","title":"\u6743\u9650\u7ba1\u7406"},{"location":"linux-command/#sudo","text":"\u4ee5 root \u6743\u9650\u6267\u884c\u547d\u4ee4\uff0c\u6bd4\u5982 sudo reboot \u53ef\u4ee5\u91cd\u542f\u673a\u5668\uff0c\u666e\u901a\u6743\u9650\u65e0\u6cd5\u91cd\u542f\u3002","title":"sudo"},{"location":"linux-command/#su","text":"\u5207\u6362\u7528\u6237\uff0c\u6bd4\u5982 sudo su ypw \u53ef\u4ee5\u5c06\u5f53\u524d\u7528\u6237\u5207\u6362\u5230 ypw \u7528\u6237\u3002","title":"su"},{"location":"linux-command/#chmod","text":"\u4fee\u6539\u6743\u9650\u7684\u547d\u4ee4\uff0c\u6bd4\u5982\uff1a sudo chmod -R 777 data \u53ef\u4ee5\u628a data \u6587\u4ef6\u5939\u4fee\u6539\u4e3a\u4efb\u4f55\u4eba\u53ef\u4ee5\u8bfb\u5199\u3002","title":"chmod"},{"location":"linux-command/#chown","text":"\u4fee\u6539\u6240\u6709\u8005\u7684\u547d\u4ee4\uff0c\u6bd4\u5982\uff1a sudo chown -R ypw data \u53ef\u4ee5\u628a data \u6587\u4ef6\u5939\u7684\u6240\u6709\u6743\u6539\u4e3a ypw\u3002","title":"chown"},{"location":"linux-command/#passwd","text":"\u4fee\u6539\u5bc6\u7801\u547d\u4ee4\uff0c\u76f4\u63a5\u6267\u884c passwd \u53ef\u4ee5\u4fee\u6539\u5f53\u524d\u7528\u6237\u5bc6\u7801\u3002 \u5f3a\u5236\u4fee\u6539\u67d0\u4e2a\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd ypw","title":"passwd"},{"location":"linux-command/#_5","text":"","title":"\u8fdb\u7a0b\u7ba1\u7406"},{"location":"linux-command/#ps","text":"ps aux \u53ef\u4ee5\u5217\u51fa\u6240\u6709\u8fdb\u7a0b\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 \u914d\u5408 grep \u547d\u4ee4\u7528\u6bd4\u8f83\u597d\uff0c\u6bd4\u5982 ps aux | grep ipython | grep -v grep \u9996\u5148\u4f7f\u7528 ps aux \u83b7\u53d6\u6240\u6709\u7684\u8fdb\u7a0b\u4fe1\u606f\uff0c\u7136\u540e\u7528 grep ipython \u67e5\u627e\u5e26\u6709 python \u7684\u8fdb\u7a0b\uff0c\u6700\u540e\u4f7f\u7528 grep -v grep \u8fc7\u6ee4 grep \u8fdb\u7a0b\u672c\u8eab\u3002","title":"ps"},{"location":"linux-command/#kill","text":"\u6740\u6389\u6267\u884c\u4e2d\u7684\u8fdb\u7a0b\uff0c\u521a\u624d ps \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u8fdb\u7a0b\u53f7\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u8fdb\u7a0b\u53f7\u5220\u9664\u8be5\u8fdb\u7a0b\uff0c\u5982 kill 8339","title":"kill"},{"location":"linux-command/#killall","text":"\u901a\u8fc7\u8fdb\u7a0b\u540d\u6765\u6740\u6389\u8fdb\u7a0b\uff0c\u8bf7\u786e\u4fdd\u4f60\u4e0d\u4f1a\u5f71\u54cd\u5176\u4ed6\u4eba\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528\u8be5\u547d\u4ee4\u3002 \u5982\u679c\u540c\u4e8b\u6b63\u5728\u4f7f\u7528 python \u8dd1\u7a0b\u5e8f\uff0c\u4f60\u4e5f\u5728\u4f7f\u7528 python \u8dd1\u7a0b\u5e8f\uff0c\u5728\u4f60\u6267\u884c\u5b8c killall python \u4ee5\u540e\uff0c\u4f60\u4eec\u7684 python \u8fdb\u7a0b\u90fd\u4f1a\u88ab\u6740\u6389\u3002","title":"killall"},{"location":"linux-command/#_6","text":"","title":"\u78c1\u76d8\u7ba1\u7406"},{"location":"linux-command/#df","text":"\u67e5\u770b\u78c1\u76d8\u7a7a\u95f4\uff0c\u6bd4\u5982 df -h \u53ef\u4ee5\u663e\u793a\u4e0b\u9762\u7684\u5185\u5bb9\uff1a Filesystem Size Used Avail Use% Mounted on udev 32G 0 32G 0% /dev tmpfs 6.3G 9.5M 6.3G 1% /run /dev/nvme0n1p2 916G 248G 622G 29% / tmpfs 32G 679M 31G 3% /dev/shm tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 32G 0 32G 0% /sys/fs/cgroup /dev/nvme0n1p1 511M 3.5M 508M 1% /boot/efi tmpfs 6.3G 32K 6.3G 1% /run/user/1000 \u4f7f\u7528 df -ih \u53ef\u4ee5\u67e5\u770b Inodes \u4f7f\u7528\u60c5\u51b5\uff0c\u5982\u679c\u4f60\u7684\u78c1\u76d8\u4e0b\u5b58\u5728\u5f88\u591a\u5c0f\u6587\u4ef6\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\u67e5\u770b\u6587\u4ef6\u8868\u662f\u5426\u7528\u5b8c\u4e86\u3002","title":"df"},{"location":"linux-command/#du","text":"\u53ef\u4ee5\u67e5\u770b\u6587\u4ef6\u5939\u5927\u5c0f\uff0c\u6bd4\u5982\uff1a du -h ImageNet \u53ef\u4ee5\u8f93\u51fa\u4e0b\u9762\u7684\u5185\u5bb9\uff1a ...... 163M ImageNet/train/n12620546 128M ImageNet/train/n02108551 127M ImageNet/train/n15075141 140G ImageNet/train 6.4G ImageNet/val 146G ImageNet","title":"du"},{"location":"linux-command/#mount","text":"\u6302\u8f7d\u78c1\u76d8\u7684\u547d\u4ee4\uff0c\u6302\u8f7d\u786c\u76d8\uff1a sudo mount -t ext4 /dev/nvme0n1p1 /data \u6302\u8f7d samba \u7f51\u7edc\u76d8\uff1a sudo mount -t cifs -o username = ypw,password = **** //192.168.8.57/dataset /home/ypw/dataset \u6ce8\u610f\uff1a\u6b64\u5904\u9700\u8981 sudo apt install cifs-utils \u3002","title":"mount"},{"location":"linux-command/#_7","text":"","title":"\u7cfb\u7edf\u7ba1\u7406"},{"location":"linux-command/#apt","text":"Ubuntu \u7cfb\u7edf\u7684\u5305\u7ba1\u7406\u5668\uff0c\u7528\u4e8e\u5b89\u88c5\u548c\u5378\u8f7d\u8f6f\u4ef6\u5305\u3002 \u5b89\u88c5\uff1a sudo apt install curl \u5378\u8f7d\uff1a sudo apt purge curl","title":"apt"},{"location":"linux-command/#export","text":"\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u547d\u4ee4\uff0c\u4e00\u822c\u5199\u5728 .bashrc \u6216 .zshrc \u6587\u4ef6\u4e2d\uff0c\u4f8b\u5982\uff1a export PATH = /usr/local/cuda/bin: $PATH \u7684\u529f\u80fd\u662f\u628a /usr/local/cuda/bin \u76ee\u5f55\u6dfb\u52a0\u5230 PATH \u7684\u6700\u524d\u9762\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u76f4\u63a5\u5728\u547d\u4ee4\u884c\u4f7f\u7528 /usr/local/cuda/bin \u76ee\u5f55\u4e0b\u7684 nvcc \u547d\u4ee4\u3002","title":"export"},{"location":"linux-command/#source","text":"\u66f4\u65b0\u73af\u5883\u53d8\u91cf\u3002 \u5982 zsh \u7528\u6237\u66f4\u65b0\u4e86 ~/.zshrc \u4ee5\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u66f4\u65b0\u73af\u5883\u53d8\u91cf\uff1a source ~/.zshrc","title":"source"},{"location":"linux-command/#update-alternatives","text":"\u5207\u6362\u547d\u4ee4\u7248\u672c\u3002\u6bd4\u5982\u4f60\u88c5\u4e86\u5f88\u591a\u4e2a CUDA \u7248\u672c\uff1a sudo update - alternatives -- config cuda There are 3 choices for the alternative cuda ( providing / usr / local / cuda ) . Selection Path Priority Status ------------------------------------------------------------ 0 / usr / local / cuda - 12 . 1 121 auto mode 1 / usr / local / cuda - 11 . 3 113 manual mode * 2 / usr / local / cuda - 11 . 7 117 manual mode 3 / usr / local / cuda - 12 . 1 121 manual mode Press < enter > to keep the current choice [ * ], or type selection number : \u4f60\u5c31\u53ef\u4ee5\u4f7f\u7528 sudo update-alternatives --config cuda \u547d\u4ee4\u9009\u62e9\u4f60\u60f3\u7528\u7684\u7248\u672c\uff0c\u8f93\u5165\u6570\u5b57\uff0c\u7136\u540e\u56de\u8f66\uff0c\u5c31\u53ef\u4ee5\u5207\u6362\u8fc7\u53bb\u3002","title":"update-alternatives"},{"location":"linux-command/#echo","text":"\u53ef\u4ee5\u8f93\u51fa\u73af\u5883\u53d8\u91cf\u3002 \u4f8b\u5982\uff1a echo $PATH","title":"echo"},{"location":"linux-command/#service","text":"\u5f00\u542f\u5173\u95ed\u670d\u52a1\u7684\u547d\u4ee4\uff0c\u5982\uff1a sudo service network-manager restart","title":"service"},{"location":"linux-command/#shutdown","text":"\u5173\u673a\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a sudo shutdown -t 0","title":"shutdown"},{"location":"linux-command/#reboot","text":"\u91cd\u542f\u547d\u4ee4\u3002 \u4f8b\u5982\uff1a sudo reboot","title":"reboot"},{"location":"linux-command/#_8","text":"","title":"\u7cfb\u7edf\u76d1\u6d4b"},{"location":"linux-command/#uname","text":"\u663e\u793a\u5f53\u524d\u7684\u7cfb\u7edf\u4fe1\u606f\u3002 uname -a \u663e\u793a\u5168\u90e8\u7684\u4fe1\u606f\uff0c\u5982\u5185\u6838\u7248\u672c\u53f7\u3001\u786c\u4ef6\u67b6\u6784\u3001\u4e3b\u673a\u540d\u79f0\u548c\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7b49\u3002","title":"uname"},{"location":"linux-command/#top","text":"\u5b9e\u65f6\u67e5\u770b\u7cfb\u7edf\u7684\u8fd0\u884c\u72b6\u6001\uff0c\u5982 CPU\u3001\u5185\u5b58\u3001\u8fdb\u7a0b\u7684\u4fe1\u606f\u3002","title":"top"},{"location":"linux-command/#ifconfig","text":"\u8fd9\u4e2a\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u5f53\u524d\u7f51\u5361\u7684 ip \u5730\u5740\u3002\u5982\uff1a \u279c ~ ifconfig | grep inet inet addr:192.168.8.100 Bcast:192.168.8.255 Mask:255.255.255.0 inet6 addr: fe80::211d:78f6:888a:1/64 Scope:Link inet addr:127.0.0.1 Mask:255.0.0.0","title":"ifconfig"},{"location":"linux-command/#free","text":"\u67e5\u770b\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff0c\u5982\uff1a free -h total used free shared buff/cache available Mem: 62G 404M 61G 9.4M 891M 61G Swap: 976M 0B 976M","title":"free"},{"location":"linux-command/#_9","text":"","title":"\u7f51\u7edc\u901a\u4fe1"},{"location":"linux-command/#ping","text":"\u6d4b\u8bd5\u4e3b\u673a\u4e4b\u95f4\u7f51\u7edc\u7684\u8fde\u901a\u6027\u3002 \u4f8b\u5982\uff1a ping baidu.com","title":"ping"},{"location":"linux-command/#ssh","text":"\u8fde\u63a5\u8fdc\u7a0b\u670d\u52a1\u5668\uff1a ssh user@192.168.1.100 \u6620\u5c04\u8fdc\u7a0b\u7aef\u53e3\uff1a ssh -L \u672c\u5730\u7aef\u53e3:\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u7aef\u53e3 \u8fdc\u7a0b\u670d\u52a1\u5668 \u4f8b\u5982\uff1a ssh -L 8888:localhost:8888 192.168.1.100 \u53ef\u4ee5\u628a\u670d\u52a1\u5668\u4e0a\u7684 jupyter \u76d1\u542c\u7684 8888 \u7aef\u53e3\u6620\u5c04\u5230\u672c\u5730\u7684 8888 \u7aef\u53e3\uff0c\u7136\u540e\u53ea\u9700\u8981\u5728\u6d4f\u89c8\u5668\u91cc\u8f93\u5165 http://localhost:8888 \u5c31\u53ef\u4ee5\u8fde\u63a5\u8fdc\u7a0b\u670d\u52a1\u5668\u7684 jupyter \u4e86\u3002","title":"ssh"},{"location":"linux-command/#scp","text":"\u590d\u5236\u6587\u4ef6/\u6587\u4ef6\u5939\u5230\u8fdc\u7a0b\u670d\u52a1\u5668\uff0c\u6216\u8005\u53cd\u5411\u590d\u5236\uff0c\u4f8b\u5982\uff1a \u4ece\u672c\u5730\u590d\u5236\u5230\u8fdc\u7a0b\uff1a scp \u672c\u5730\u6587\u4ef6 \u7528\u6237\u540d@\u76ee\u6807\u4e3b\u673a:\u76ee\u6807\u4e3b\u673a\u8def\u5f84 \u4ece\u8fdc\u7a0b\u590d\u5236\u5230\u672c\u5730\uff1a scp \u7528\u6237\u540d@\u76ee\u6807\u4e3b\u673a:\u76ee\u6807\u4e3b\u673a\u6587\u4ef6 \u672c\u5730\u5730\u5740 \u590d\u5236\u6587\u4ef6\uff1a scp filename user@192.168.1.100:/data \u590d\u5236\u6587\u4ef6\u5939\u9700\u8981\u6dfb\u52a0 -r \u53c2\u6570\uff1a scp -r directory user@192.168.1.100:/data \u5f53\u4f60\u590d\u5236\u5927\u91cf\u5c0f\u6587\u4ef6\u65f6\uff0c\u8bf7\u4f7f\u7528 rsync \u547d\u4ee4\u3002","title":"scp"},{"location":"linux-command/#rsync","text":"\u540c\u6b65\u6587\u4ef6/\u6587\u4ef6\u5939\u547d\u4ee4\uff0c\u5e26\u6709\u589e\u91cf\u5907\u4efd\u529f\u80fd\uff0c\u901f\u5ea6\u5f88\u5feb\u3002 \u53c2\u6570\uff1a -a\uff0c--archive \u5f52\u6863\u6a21\u5f0f\uff0c\u8868\u793a\u4ee5\u9012\u5f52\u65b9\u5f0f\u4f20\u8f93\u6587\u4ef6\uff0c\u5e76\u4fdd\u6301\u6240\u6709\u6587\u4ef6\u5c5e\u6027\uff0c\u7b49\u4e8e-rlptgoD\u3002 -v\uff0c--verbose \u8be6\u7ec6\u6a21\u5f0f\u8f93\u51fa\u3002 -z\uff0c--compress \u5728\u4f20\u8f93\u65f6\u538b\u7f29\u6570\u636e\uff0c\u5982\u679c\u4f60\u4f20\u8f93\u7684\u6587\u4ef6\u6ca1\u6709\u538b\u7f29\u8fc7\uff0c\u5e76\u4e14\u5e26\u5bbd\u4e0d\u591f\u5927\uff0c\u5c31\u53ef\u4ee5\u5f00\u542f\u538b\u7f29\u3002\u5982\u679c\u4f60\u4f20\u8f93\u7684\u662f\u56fe\u50cf\u6587\u4ef6\uff0c\u90a3\u4e48\u538b\u7f29\u4f1a\u62d6\u6162\u4f20\u8f93\u901f\u5ea6\u3002 --delete\uff0c\u5728\u540c\u6b65\u7684\u65f6\u5019\u5220\u9664\u591a\u4f59\u7684\u6587\u4ef6\uff0c\u8fd9\u53ef\u4ee5\u786e\u4fdd\u4e24\u4e2a\u6587\u4ef6\u5939\u7684\u4e00\u81f4\u6027\u3002 --exclude\uff0c\u6392\u9664\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u901a\u914d\u7b26 -P\uff0c\u7b49\u540c\u4e8e --partial --progress\uff0c\u663e\u793a\u5907\u4efd\u8fc7\u7a0b\u3002 \u547d\u4ee4\uff1a rsync -avP \u6e90\u8def\u5f84 \u76ee\u7684\u5730\u8def\u5f84 \uff0c\u5176\u4e2d\u6e90\u8def\u5f84\u53ef\u4ee5\u662f\u672c\u5730\u6587\u4ef6\u5939\u8def\u5f84\uff0c\u4e5f\u53ef\u4ee5\u662f\u8fdc\u7a0b\u8def\u5f84\uff0c\u76ee\u7684\u5730\u8def\u5f84\u4e5f\u53ef\u4ee5\u662f\u672c\u5730\u548c\u8fdc\u7a0b\u8def\u5f84\u3002 \u5982\uff1a \u5c06\u672c\u5730\u7684\u6587\u4ef6\u5939\u540c\u6b65\u5230\u670d\u52a1\u5668\uff1a rsync -avP \u672c\u5730\u8def\u5f84 \u7528\u6237\u540d@\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u8def\u5f84 \u5c06\u670d\u52a1\u5668\u4e0a\u7684\u6587\u4ef6\u5939\u540c\u6b65\u5230\u672c\u5730\uff1a rsync -avP \u7528\u6237\u540d@\u8fdc\u7a0b\u670d\u52a1\u5668:\u8fdc\u7a0b\u8def\u5f84 \u672c\u5730\u8def\u5f84 \u672c\u5730\u62f7\u8d1d\u6587\u4ef6\u5939\uff1a rsync -avP \u672c\u5730\u6e90\u8def\u5f84 \u672c\u5730\u76ee\u7684\u5730\u8def\u5f84 \u6ce8\u610f\uff1a \u5982\u679c\u540c\u6b65\u7684\u6e90\u8def\u5f84\u540e\u9762\u52a0\u4e86\u659c\u6760 / \uff0c\u5219\u540c\u6b65\u7684\u76ee\u7684\u5730\u4e0d\u4f1a\u521b\u5efa\u5b50\u6587\u4ef6\u5939\u3002\u6bd4\u5982\u5c06\u4e00\u53f0\u670d\u52a1\u5668\u4e0a\u7684 home \u76ee\u5f55\u540c\u6b65\u53e6\u4e00\u53f0\u670d\u52a1\u5668\uff1a rsync -avP \u914d\u597d\u7684\u670d\u52a1\u5668:/home/ypw/ . \u4e0b\u9762\u662f\u4e00\u4e2a\u628a\u8fdc\u7a0b\u670d\u52a1\u5668\u540c\u6b65\u5230\u672c\u5730\u7684\u4f8b\u5b50\uff1a","title":"rsync"},{"location":"linux-command/#wget","text":"\u4ece\u6307\u5b9a\u7684URL\u4e0b\u8f7d\u6587\u4ef6\u3002 \u4e0b\u8f7d\u5355\u4e2a\u6587\u4ef6\uff1a wget url \u4e0b\u8f7d\u5e76\u4fee\u6539\u6587\u4ef6\u540d\uff1a wget -O filename.zip url","title":"wget"},{"location":"mac-compare/","text":"Mac \u5bf9\u6bd4 \u8fd9\u90e8\u5206\u4e3b\u8981\u4ecb\u7ecd\u82f9\u679c\u516c\u53f8\u7684\u7535\u8111\u4ea7\u54c1\uff0c\u4ee5\u53ca\u6211\u6b63\u5728\u4f7f\u7528\u7684\u8bbe\u5907\u3002 \u4e0b\u9762\u7684\u8868\u683c\u662f\u4ecb\u7ecd\u6bcf\u4e2a\u4ea7\u54c1\u4e0d\u540c\u914d\u7f6e\u7684\u60c5\u51b5\uff08\u622a\u6b62\u81f3 2019\u5e7411\u670813\u65e5\uff09\uff1a \u578b\u53f7 CPU(GHz) \u5185\u5b58(GB) \u5b58\u50a8\u5bb9\u91cf(GB) \u5c4f\u5e55(\u5bf8) \u91cd\u91cf(\u5343\u514b) \u4ef7\u683c(\u5143) MacBook 1.2(3.0)*2 8 256 12 0.92 \u4e70\u4e0d\u5230\u4e86 MacBook Air 1.6(3.6)*2 8 128 13 1.25 8899 MacBook Pro 13 1.4(3.9)*4 8 128 13 1.37 9999 MacBook Pro 13 2.4(4.1)*4 8 256 13 1.37 13899 MacBook Pro 16 2.6(4.5)*6 16 512 16 2.0 18999 MacBook Pro 16 2.3(4.8)*8 16 1024 16 2.0 22199 Mac mini 3.6*4 8 128 \u65e0 1.3 6331 Mac mini 3.0(4.1)*6 8 256 \u65e0 1.3 8669 iMac 27 3.0(4.1)*6 8 1024(\u878d\u5408) 27 9.42 13832 iMac 27 (\u5b9a\u5236) 3.6(5.0)*8 8 512 27 9.42 21398 iMac Pro 3.2(4.2)*8 32 1024 27 9.7 38138 Mac Pro (\u672a\u53d1\u552e) 3.5(4)*8 32 256 \u65e0 18 \u7ea64\u4e07(5999$) \u6ce8\uff1a CPU \u62ec\u53f7\u91cc\u7684\u6570\u5b57\u4e3a Turbo Boost \u4ee5\u540e\u7684\u9891\u7387\uff0c\u540e\u9762\u4e58\u7684\u6570\u5b57\u4ee3\u8868\u6838\u6570 iMac \u4e0d\u5b9a\u5236\u53ea\u80fd\u4e70\u5230\u975e\u56fa\u6001\u786c\u76d8 Mac Pro \u6682\u672a\u53d1\u552e \u8be6\u7ec6\u4fe1\u606f\u8bf7\u67e5\u770b\u5b98\u7f51\uff1a https://www.apple.com/cn/mac/ https://www.apple.com/cn/mac/compare/ \u4e0b\u9762\u8ba9\u6211\u4eec\u8be6\u7ec6\u4ecb\u7ecd\u8fd9\u51e0\u4e2a\u578b\u53f7\uff0c\u4ee5\u53ca\u6211\u7684\u4f53\u9a8c\u548c\u60f3\u6cd5\u3002 MacBook \u4ece\u4e0a\u9762\u7684\u8868\u683c\u53ef\u4ee5\u770b\u5230\uff0cMacBook \u7684 CPU \u9891\u7387\u662f\u5f88\u4f4e\u7684\uff0c\u8fd9\u662f\u56e0\u4e3a\u6ca1\u6709\u98ce\u6247\uff0c\u6240\u4ee5 CPU \u529f\u7387\u975e\u5e38\u4f4e\u3002\u8fd9\u6b3e\u7b14\u8bb0\u672c\u7684\u4e3b\u8981\u4f18\u52bf\u5728\u4e8e\u4fbf\u643a\uff0c\u91cd\u91cf\u53ea\u6709 0.92\u5343\u514b\uff0c\u662f\u82f9\u679c\u6700\u8f7b\u7684\u7b14\u8bb0\u672c\u3002\u5b83\u975e\u5e38\u9002\u5408\u51fa\u5dee\u7684\u65f6\u5019\u5e26\u4e0a\u3002\u7528\u82f9\u679c\u7684\u8bdd\u8bf4\u5c31\u662f\u201c\u8eab\u8584\u529b\u4e0d\u8584\u201d\uff0c\u7528\u4fd7\u8bdd\u8bf4\u5c31\u662f\u9ebb\u96c0\u867d\u5c0f\u4e94\u810f\u4ff1\u5168\u3002 \u5199\u4ee3\u7801\u7684\u4f53\u9a8c\u4e0a\u6765\u8bf4\uff0c\u4f7f\u7528\u8d77\u6765\u9664\u4e86\u5c4f\u5e55\u5c0f\uff0c\u6ca1\u6709\u7f3a\u70b9\uff0c\u56e0\u4e3a\u4ee3\u7801\u90fd\u662f\u8fdc\u7a0b\u6267\u884c\u7684\uff0c\u6240\u4ee5\u5b83\u53ea\u8d1f\u8d23\u663e\u793a\u4ee3\u7801\uff0c\u8fdb\u884c\u4ee3\u7801\u63d0\u793a\uff0c\u628a\u4fee\u6539\u8fc7\u4ee3\u7801\u63a8\u5230\u670d\u52a1\u5668\u4e0a\u5373\u53ef\u3002\u6211\u751a\u81f3\u7528\u5b83\u8dd1\u8fc7 Windows \u865a\u62df\u673a\uff0c\u9664\u4e86\u6162\u4e00\u70b9\uff0c\u6ca1\u6709\u4efb\u4f55\u5176\u4ed6\u95ee\u9898\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5b83\u53ea\u6709\u4e00\u4e2a USB-C \u53e3\u3002 \u6b64\u6b3e\u662f\u6211\u7684\u65c5\u884c\u5fc5\u5907\u3002 2019\u5e74\u6ce8\uff1a\u6b64\u6b3e\u5df2\u7ecf\u4e0d\u5356\u4e86\uff0c\u53ef\u4ee5\u8d2d\u4e70 MacBook Air\u3002 MacBook Air MacBook Air \u7684\u4ef7\u683c\u6bd4 MacBook \u4fbf\u5b9c\u4e00\u70b9\uff0c\u6027\u80fd\u6bd4 MacBook \u597d\u4e00\u70b9\uff0c\u4f46\u662f\u91cd\u91cf\u91cd\u4e00\u70b9\uff0c\u591a\u4e00\u4e2a USB-C \u53e3\uff0c\u7136\u540e\u5c31\u6ca1\u6709\u5176\u4ed6\u7684\u4f18\u52bf\u4e86\u3002\u5373\u4f7f\u662f MacBook Pro \u7684\u53cc\u6838\u5165\u95e8\u6b3e\uff0c\u91cd\u91cf\u4e0e MacBook Air \u5dee\u4e0d\u591a\uff0cCPU \u5374\u597d\u4e86\u4e0d\u5c11\uff0c\u6240\u4ee5\u6211\u6ca1\u6709\u4e70\u8fc7\u8fd9\u4e00\u6b3e\u3002 MacBook Pro \u5982\u679c\u662f\u5b66\u751f\u515a\uff0c\u4e3b\u63a8 MacBook Pro\u3002 \u4ece\u8868\u683c\u4e2d\u53ef\u4ee5\u770b\u5230\uff0c\u4ece\u4e00\u4e07\u5230\u4e24\u4e07\u90fd\u6709\u7684\u9009\uff0c\u6027\u80fd\u4e5f\u4ece 2 \u6838\u5230 8 \u6838\uff0c\u5dee\u4e86\u51e0\u500d\u3002\u4e00\u822c\u6765\u8bf4\u8fd8\u662f\u9009\u80fd\u4e70\u5f97\u8d77\u7684\u6700\u8d35\u7684\u578b\u53f7\u6bd4\u8f83\u597d\uff0c\u4e00\u6b65\u5230\u4f4d\u514d\u9664\u540e\u60a3\u3002 \u5f53\u4f60\u4f7f\u7528 PyCharm \u5199\u4ee3\u7801\u7684\u65f6\u5019\uff0c\u4ee3\u7801\u63d0\u793a\u3001Debug \u4e0b\u65ad\u70b9\u4ee5\u53ca Debug \u53d8\u91cf\u5185\u5bb9\u7684\u663e\u793a\u90fd\u4f1a\u6bd4\u8f83\u8017\u8d39CPU\uff0c\u5c3d\u53ef\u80fd\u4e70\u4e00\u4e2a\u901f\u5ea6\u5feb\u7684\u7535\u8111\u80fd\u591f\u8282\u7701\u751f\u547d\u3002 \u6b63\u5e38\u64cd\u4f5c\u7cfb\u7edf\u5f00\u673a\u4ee5\u540e\u90fd\u4f1a\u5360\u7528 6GB \u5de6\u53f3\u7684\u5185\u5b58\uff0cPyCharm \u9ed8\u8ba4\u6d88\u8017 750MB\u5185\u5b58\uff0c\u4e0d\u8fc7\u6211\u4f7f\u7528\u7684\u65f6\u5019\u901a\u5e38\u4f1a\u5185\u5b58\u4e0d\u8db3\uff0c\u6240\u4ee5\u6211\u4f1a\u8c03\u5230 2GB\uff0c\u8fd9\u6837\u5c31\u4f1a\u7528\u5149 8GB \u5185\u5b58\uff0c\u56e0\u6b64\u9009\u62e9 16GB \u5185\u5b58\u662f\u6bd4\u8f83\u5145\u88d5\u7684\u3002 \u4e2a\u4eba\u89c9\u5f97\u5982\u679c\u4e0d\u653e\u6570\u636e\u96c6\uff0c\u786c\u76d8\u9009 256GB \u662f\u591f\u7528\u7684\u3002\u5982\u679c\u4f60\u4f5c\u4e3a\u4e3b\u529b\u673a\u4f7f\u7528\uff0c\u9664\u4e86\u5199\u4ee3\u7801\u8fd8\u9700\u8981\u653e\u7535\u89c6\u5267\u3001\u7167\u7247\u3001\u624b\u673a\u5907\u4efd\u7b49\u6587\u4ef6\uff0c\u90a3\u4e48\u6700\u597d\u6309\u7167\u81ea\u5df1\u7684\u4f7f\u7528\u4e60\u60ef\u53bb\u9009\u62e9\u5408\u9002\u7684\u5bb9\u91cf\u3002 \u6211\u91cd\u5ea6\u4f7f\u7528\u8fc7 13\u5bf8\u548c 15\u5bf8\u7684\u578b\u53f7\u3002 Mac mini \u6b64\u6b3e\u4e0a\u73ed\u65cf\u53ef\u4ee5\u8003\u8651\uff0c\u5b83\u7684\u4ef7\u683c\u4fbf\u5b9c\uff0c\u6027\u4ef7\u6bd4\u5374\u5f88\u9ad8\uff0c\u516b\u5343\u7684\u4ef7\u683c\u53ef\u4ee5\u6bd4\u5f97\u4e0a\u4e00\u4e07\u516b\u7684 MacBook Pro \u7684\u6027\u80fd\uff0c\u4e0d\u8fc7\u6211\u6ca1\u6709\u4e70\u8fc7\uff0c\u6240\u4ee5\u4e0d\u505a\u8fc7\u591a\u7684\u8bc4\u8bba\u4e86\u3002 iMac \u8fd9\u662f\u6211\u6700\u559c\u6b22\u7684 Mac\uff0c\u56e0\u4e3a\u5b83\u7684\u5c4f\u5e55\u7279\u522b\u5927\uff0c\u5206\u8fa8\u7387\u4e5f\u9ad8\uff085K\uff09\uff0c\u975e\u5e38\u9002\u5408\u5199\u4ee3\u7801\u3002\u6211\u4e70\u7684\u662f\u5b9a\u5236\u7684 1TB\u56fa\u6001\u786c\u76d8\uff0c\u53e6\u5916\u5347\u7ea7 CPU \u4e3a i7\u3002\u73b0\u5728\u4e70\u7684\u8bdd\uff0c\u80fd\u591f\u5347\u7ea7\u5230 i9\uff0c\u6027\u80fd\u6bd4\u6211\u6b63\u5728\u4f7f\u7528\u7684\u8fd9\u53f0\u597d\u5f97\u591a\uff0c\u5341\u5206\u63a8\u8350\u3002 \u5185\u5b58\u6761\u53ef\u4ee5\u5728\u7f51\u4e0a\u8d2d\u4e70\uff0c\u81ea\u884c\u5b89\u88c5\uff0c\u975e\u5e38\u65b9\u4fbf\uff0c\u8fd9\u91cc\u4e0d\u5efa\u8bae\u5347\u7ea7\u3002 \u786c\u76d8\u5f3a\u70c8\u5efa\u8bae\u9009\u56fa\u6001\u786c\u76d8\uff0c\u6781\u5927\u63d0\u5347\u5404\u5927 APP \u7684\u542f\u52a8\u901f\u5ea6\u4ee5\u53ca\u54cd\u5e94\u901f\u5ea6\u3002 \u9f20\u6807\u4e0d\u63a8\u8350\uff0c\u5efa\u8bae\u9009\u89e6\u63a7\u677f\uff0c\u719f\u7ec3\u4f7f\u7528\u89e6\u63a7\u677f\u53ef\u4ee5\u9ad8\u6548\u8fdb\u884c\u5404\u79cd\u64cd\u4f5c\uff0c\u6bd4\u5982\u62d6\u62fd\u3001\u591a\u9009\u3001\u5207\u6362\u5e94\u7528\u548c\u5c4f\u5e55\u7b49\u3002 iMac Pro \u6027\u80fd\u66f4\u597d\u4e86\uff0c\u4f46\u662f\u4ef7\u683c\u4e5f\u7ffb\u500d\u4e86\uff0c\u6027\u4ef7\u6bd4\u4e0d\u9ad8\u3002\u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u6765\u8bf4\u6ca1\u6709\u66f4\u5927\u7684\u4f18\u52bf\uff0c\u4e0d\u8fc7\u5982\u679c\u4e0d\u8ba1\u6210\u672c\u53c8\u559c\u6b22\u9ed1\u8272\u7684\u8bdd\u53ef\u4ee5\u9009\u62e9\u8fd9\u6b3e\u3002 Mac Pro \u6027\u80fd\u5f88\u5f3a\u5927\uff0c\u4f46\u662f\u73b0\u5728\u4e70\u4e0d\u5230\uff0c\u5355\u770b\u4f4e\u914d\u7248\u7684\u6027\u80fd\u6bd4\u4e0d\u8fc7 iMac \u5b9a\u5236\u7248\u3002 \u5982\u679c\u9009\u914d\u66f4\u9ad8\u7ea7\u522b\u7684\u914d\u7f6e\uff0c\u6bd4\u5982\u52a0\u4e2a Radeon Pro Vega II Duo\uff0c\u636e\u8bf4\u6709 14TFLOPS \u7684\u6027\u80fd\uff0c\u6216\u8bb8\u53ef\u4ee5\u76f4\u63a5\u8dd1\u6df1\u5ea6\u5b66\u4e60\uff0c\u4f46\u662f\u662f A \u5361\uff0c\u53ef\u80fd\u9700\u8981\u8e29\u5751\u3002\u7b49\u5230 CoreML \u80fd\u8bad\u7ec3\u6a21\u578b\u7684\u65f6\u5019\uff0c\u6216\u8bb8\u53ef\u4ee5\u4e70\u4e00\u4e2a\u8bd5\u8bd5\u770b\u3002 \u603b\u7ed3 \u5b66\u751f\u515a\u6309\u9884\u7b97\u9009\u62e9\u4e70\u5f97\u8d77\u7684\u6700\u597d\u7684 MacBook Pro\uff0c\u6709\u56fa\u5b9a\u5de5\u4f4d\u7684\u5b66\u751f\u6216\u4e0a\u73ed\u65cf\u53ef\u4ee5\u8003\u8651\u4e70 iMac \u6216\u8005 Mac mini\uff0c\u8ffd\u6c42\u8f7b\u4fbf\u53ef\u4ee5\u9009 MacBook\u3002 \u6700\u4f73\u642d\u914d\u662f\u5bb6\u91cc\u653e\u4e00\u53f0 iMac\uff0c\u51fa\u95e8\u4f7f\u7528 MacBook\uff0c\u4f7f\u7528 iCloud \u8fdb\u884c\u8bbe\u5907\u4e4b\u95f4\u7684\u6587\u4ef6\u540c\u6b65\u3002","title":"Mac \u5bf9\u6bd4"},{"location":"mac-compare/#mac","text":"\u8fd9\u90e8\u5206\u4e3b\u8981\u4ecb\u7ecd\u82f9\u679c\u516c\u53f8\u7684\u7535\u8111\u4ea7\u54c1\uff0c\u4ee5\u53ca\u6211\u6b63\u5728\u4f7f\u7528\u7684\u8bbe\u5907\u3002 \u4e0b\u9762\u7684\u8868\u683c\u662f\u4ecb\u7ecd\u6bcf\u4e2a\u4ea7\u54c1\u4e0d\u540c\u914d\u7f6e\u7684\u60c5\u51b5\uff08\u622a\u6b62\u81f3 2019\u5e7411\u670813\u65e5\uff09\uff1a \u578b\u53f7 CPU(GHz) \u5185\u5b58(GB) \u5b58\u50a8\u5bb9\u91cf(GB) \u5c4f\u5e55(\u5bf8) \u91cd\u91cf(\u5343\u514b) \u4ef7\u683c(\u5143) MacBook 1.2(3.0)*2 8 256 12 0.92 \u4e70\u4e0d\u5230\u4e86 MacBook Air 1.6(3.6)*2 8 128 13 1.25 8899 MacBook Pro 13 1.4(3.9)*4 8 128 13 1.37 9999 MacBook Pro 13 2.4(4.1)*4 8 256 13 1.37 13899 MacBook Pro 16 2.6(4.5)*6 16 512 16 2.0 18999 MacBook Pro 16 2.3(4.8)*8 16 1024 16 2.0 22199 Mac mini 3.6*4 8 128 \u65e0 1.3 6331 Mac mini 3.0(4.1)*6 8 256 \u65e0 1.3 8669 iMac 27 3.0(4.1)*6 8 1024(\u878d\u5408) 27 9.42 13832 iMac 27 (\u5b9a\u5236) 3.6(5.0)*8 8 512 27 9.42 21398 iMac Pro 3.2(4.2)*8 32 1024 27 9.7 38138 Mac Pro (\u672a\u53d1\u552e) 3.5(4)*8 32 256 \u65e0 18 \u7ea64\u4e07(5999$) \u6ce8\uff1a CPU \u62ec\u53f7\u91cc\u7684\u6570\u5b57\u4e3a Turbo Boost \u4ee5\u540e\u7684\u9891\u7387\uff0c\u540e\u9762\u4e58\u7684\u6570\u5b57\u4ee3\u8868\u6838\u6570 iMac \u4e0d\u5b9a\u5236\u53ea\u80fd\u4e70\u5230\u975e\u56fa\u6001\u786c\u76d8 Mac Pro \u6682\u672a\u53d1\u552e \u8be6\u7ec6\u4fe1\u606f\u8bf7\u67e5\u770b\u5b98\u7f51\uff1a https://www.apple.com/cn/mac/ https://www.apple.com/cn/mac/compare/ \u4e0b\u9762\u8ba9\u6211\u4eec\u8be6\u7ec6\u4ecb\u7ecd\u8fd9\u51e0\u4e2a\u578b\u53f7\uff0c\u4ee5\u53ca\u6211\u7684\u4f53\u9a8c\u548c\u60f3\u6cd5\u3002","title":"Mac \u5bf9\u6bd4"},{"location":"mac-compare/#macbook","text":"\u4ece\u4e0a\u9762\u7684\u8868\u683c\u53ef\u4ee5\u770b\u5230\uff0cMacBook \u7684 CPU \u9891\u7387\u662f\u5f88\u4f4e\u7684\uff0c\u8fd9\u662f\u56e0\u4e3a\u6ca1\u6709\u98ce\u6247\uff0c\u6240\u4ee5 CPU \u529f\u7387\u975e\u5e38\u4f4e\u3002\u8fd9\u6b3e\u7b14\u8bb0\u672c\u7684\u4e3b\u8981\u4f18\u52bf\u5728\u4e8e\u4fbf\u643a\uff0c\u91cd\u91cf\u53ea\u6709 0.92\u5343\u514b\uff0c\u662f\u82f9\u679c\u6700\u8f7b\u7684\u7b14\u8bb0\u672c\u3002\u5b83\u975e\u5e38\u9002\u5408\u51fa\u5dee\u7684\u65f6\u5019\u5e26\u4e0a\u3002\u7528\u82f9\u679c\u7684\u8bdd\u8bf4\u5c31\u662f\u201c\u8eab\u8584\u529b\u4e0d\u8584\u201d\uff0c\u7528\u4fd7\u8bdd\u8bf4\u5c31\u662f\u9ebb\u96c0\u867d\u5c0f\u4e94\u810f\u4ff1\u5168\u3002 \u5199\u4ee3\u7801\u7684\u4f53\u9a8c\u4e0a\u6765\u8bf4\uff0c\u4f7f\u7528\u8d77\u6765\u9664\u4e86\u5c4f\u5e55\u5c0f\uff0c\u6ca1\u6709\u7f3a\u70b9\uff0c\u56e0\u4e3a\u4ee3\u7801\u90fd\u662f\u8fdc\u7a0b\u6267\u884c\u7684\uff0c\u6240\u4ee5\u5b83\u53ea\u8d1f\u8d23\u663e\u793a\u4ee3\u7801\uff0c\u8fdb\u884c\u4ee3\u7801\u63d0\u793a\uff0c\u628a\u4fee\u6539\u8fc7\u4ee3\u7801\u63a8\u5230\u670d\u52a1\u5668\u4e0a\u5373\u53ef\u3002\u6211\u751a\u81f3\u7528\u5b83\u8dd1\u8fc7 Windows \u865a\u62df\u673a\uff0c\u9664\u4e86\u6162\u4e00\u70b9\uff0c\u6ca1\u6709\u4efb\u4f55\u5176\u4ed6\u95ee\u9898\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5b83\u53ea\u6709\u4e00\u4e2a USB-C \u53e3\u3002 \u6b64\u6b3e\u662f\u6211\u7684\u65c5\u884c\u5fc5\u5907\u3002 2019\u5e74\u6ce8\uff1a\u6b64\u6b3e\u5df2\u7ecf\u4e0d\u5356\u4e86\uff0c\u53ef\u4ee5\u8d2d\u4e70 MacBook Air\u3002","title":"MacBook"},{"location":"mac-compare/#macbook-air","text":"MacBook Air \u7684\u4ef7\u683c\u6bd4 MacBook \u4fbf\u5b9c\u4e00\u70b9\uff0c\u6027\u80fd\u6bd4 MacBook \u597d\u4e00\u70b9\uff0c\u4f46\u662f\u91cd\u91cf\u91cd\u4e00\u70b9\uff0c\u591a\u4e00\u4e2a USB-C \u53e3\uff0c\u7136\u540e\u5c31\u6ca1\u6709\u5176\u4ed6\u7684\u4f18\u52bf\u4e86\u3002\u5373\u4f7f\u662f MacBook Pro \u7684\u53cc\u6838\u5165\u95e8\u6b3e\uff0c\u91cd\u91cf\u4e0e MacBook Air \u5dee\u4e0d\u591a\uff0cCPU \u5374\u597d\u4e86\u4e0d\u5c11\uff0c\u6240\u4ee5\u6211\u6ca1\u6709\u4e70\u8fc7\u8fd9\u4e00\u6b3e\u3002","title":"MacBook Air"},{"location":"mac-compare/#macbook-pro","text":"\u5982\u679c\u662f\u5b66\u751f\u515a\uff0c\u4e3b\u63a8 MacBook Pro\u3002 \u4ece\u8868\u683c\u4e2d\u53ef\u4ee5\u770b\u5230\uff0c\u4ece\u4e00\u4e07\u5230\u4e24\u4e07\u90fd\u6709\u7684\u9009\uff0c\u6027\u80fd\u4e5f\u4ece 2 \u6838\u5230 8 \u6838\uff0c\u5dee\u4e86\u51e0\u500d\u3002\u4e00\u822c\u6765\u8bf4\u8fd8\u662f\u9009\u80fd\u4e70\u5f97\u8d77\u7684\u6700\u8d35\u7684\u578b\u53f7\u6bd4\u8f83\u597d\uff0c\u4e00\u6b65\u5230\u4f4d\u514d\u9664\u540e\u60a3\u3002 \u5f53\u4f60\u4f7f\u7528 PyCharm \u5199\u4ee3\u7801\u7684\u65f6\u5019\uff0c\u4ee3\u7801\u63d0\u793a\u3001Debug \u4e0b\u65ad\u70b9\u4ee5\u53ca Debug \u53d8\u91cf\u5185\u5bb9\u7684\u663e\u793a\u90fd\u4f1a\u6bd4\u8f83\u8017\u8d39CPU\uff0c\u5c3d\u53ef\u80fd\u4e70\u4e00\u4e2a\u901f\u5ea6\u5feb\u7684\u7535\u8111\u80fd\u591f\u8282\u7701\u751f\u547d\u3002 \u6b63\u5e38\u64cd\u4f5c\u7cfb\u7edf\u5f00\u673a\u4ee5\u540e\u90fd\u4f1a\u5360\u7528 6GB \u5de6\u53f3\u7684\u5185\u5b58\uff0cPyCharm \u9ed8\u8ba4\u6d88\u8017 750MB\u5185\u5b58\uff0c\u4e0d\u8fc7\u6211\u4f7f\u7528\u7684\u65f6\u5019\u901a\u5e38\u4f1a\u5185\u5b58\u4e0d\u8db3\uff0c\u6240\u4ee5\u6211\u4f1a\u8c03\u5230 2GB\uff0c\u8fd9\u6837\u5c31\u4f1a\u7528\u5149 8GB \u5185\u5b58\uff0c\u56e0\u6b64\u9009\u62e9 16GB \u5185\u5b58\u662f\u6bd4\u8f83\u5145\u88d5\u7684\u3002 \u4e2a\u4eba\u89c9\u5f97\u5982\u679c\u4e0d\u653e\u6570\u636e\u96c6\uff0c\u786c\u76d8\u9009 256GB \u662f\u591f\u7528\u7684\u3002\u5982\u679c\u4f60\u4f5c\u4e3a\u4e3b\u529b\u673a\u4f7f\u7528\uff0c\u9664\u4e86\u5199\u4ee3\u7801\u8fd8\u9700\u8981\u653e\u7535\u89c6\u5267\u3001\u7167\u7247\u3001\u624b\u673a\u5907\u4efd\u7b49\u6587\u4ef6\uff0c\u90a3\u4e48\u6700\u597d\u6309\u7167\u81ea\u5df1\u7684\u4f7f\u7528\u4e60\u60ef\u53bb\u9009\u62e9\u5408\u9002\u7684\u5bb9\u91cf\u3002 \u6211\u91cd\u5ea6\u4f7f\u7528\u8fc7 13\u5bf8\u548c 15\u5bf8\u7684\u578b\u53f7\u3002","title":"MacBook Pro"},{"location":"mac-compare/#mac-mini","text":"\u6b64\u6b3e\u4e0a\u73ed\u65cf\u53ef\u4ee5\u8003\u8651\uff0c\u5b83\u7684\u4ef7\u683c\u4fbf\u5b9c\uff0c\u6027\u4ef7\u6bd4\u5374\u5f88\u9ad8\uff0c\u516b\u5343\u7684\u4ef7\u683c\u53ef\u4ee5\u6bd4\u5f97\u4e0a\u4e00\u4e07\u516b\u7684 MacBook Pro \u7684\u6027\u80fd\uff0c\u4e0d\u8fc7\u6211\u6ca1\u6709\u4e70\u8fc7\uff0c\u6240\u4ee5\u4e0d\u505a\u8fc7\u591a\u7684\u8bc4\u8bba\u4e86\u3002","title":"Mac mini"},{"location":"mac-compare/#imac","text":"\u8fd9\u662f\u6211\u6700\u559c\u6b22\u7684 Mac\uff0c\u56e0\u4e3a\u5b83\u7684\u5c4f\u5e55\u7279\u522b\u5927\uff0c\u5206\u8fa8\u7387\u4e5f\u9ad8\uff085K\uff09\uff0c\u975e\u5e38\u9002\u5408\u5199\u4ee3\u7801\u3002\u6211\u4e70\u7684\u662f\u5b9a\u5236\u7684 1TB\u56fa\u6001\u786c\u76d8\uff0c\u53e6\u5916\u5347\u7ea7 CPU \u4e3a i7\u3002\u73b0\u5728\u4e70\u7684\u8bdd\uff0c\u80fd\u591f\u5347\u7ea7\u5230 i9\uff0c\u6027\u80fd\u6bd4\u6211\u6b63\u5728\u4f7f\u7528\u7684\u8fd9\u53f0\u597d\u5f97\u591a\uff0c\u5341\u5206\u63a8\u8350\u3002 \u5185\u5b58\u6761\u53ef\u4ee5\u5728\u7f51\u4e0a\u8d2d\u4e70\uff0c\u81ea\u884c\u5b89\u88c5\uff0c\u975e\u5e38\u65b9\u4fbf\uff0c\u8fd9\u91cc\u4e0d\u5efa\u8bae\u5347\u7ea7\u3002 \u786c\u76d8\u5f3a\u70c8\u5efa\u8bae\u9009\u56fa\u6001\u786c\u76d8\uff0c\u6781\u5927\u63d0\u5347\u5404\u5927 APP \u7684\u542f\u52a8\u901f\u5ea6\u4ee5\u53ca\u54cd\u5e94\u901f\u5ea6\u3002 \u9f20\u6807\u4e0d\u63a8\u8350\uff0c\u5efa\u8bae\u9009\u89e6\u63a7\u677f\uff0c\u719f\u7ec3\u4f7f\u7528\u89e6\u63a7\u677f\u53ef\u4ee5\u9ad8\u6548\u8fdb\u884c\u5404\u79cd\u64cd\u4f5c\uff0c\u6bd4\u5982\u62d6\u62fd\u3001\u591a\u9009\u3001\u5207\u6362\u5e94\u7528\u548c\u5c4f\u5e55\u7b49\u3002","title":"iMac"},{"location":"mac-compare/#imac-pro","text":"\u6027\u80fd\u66f4\u597d\u4e86\uff0c\u4f46\u662f\u4ef7\u683c\u4e5f\u7ffb\u500d\u4e86\uff0c\u6027\u4ef7\u6bd4\u4e0d\u9ad8\u3002\u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u6765\u8bf4\u6ca1\u6709\u66f4\u5927\u7684\u4f18\u52bf\uff0c\u4e0d\u8fc7\u5982\u679c\u4e0d\u8ba1\u6210\u672c\u53c8\u559c\u6b22\u9ed1\u8272\u7684\u8bdd\u53ef\u4ee5\u9009\u62e9\u8fd9\u6b3e\u3002","title":"iMac Pro"},{"location":"mac-compare/#mac-pro","text":"\u6027\u80fd\u5f88\u5f3a\u5927\uff0c\u4f46\u662f\u73b0\u5728\u4e70\u4e0d\u5230\uff0c\u5355\u770b\u4f4e\u914d\u7248\u7684\u6027\u80fd\u6bd4\u4e0d\u8fc7 iMac \u5b9a\u5236\u7248\u3002 \u5982\u679c\u9009\u914d\u66f4\u9ad8\u7ea7\u522b\u7684\u914d\u7f6e\uff0c\u6bd4\u5982\u52a0\u4e2a Radeon Pro Vega II Duo\uff0c\u636e\u8bf4\u6709 14TFLOPS \u7684\u6027\u80fd\uff0c\u6216\u8bb8\u53ef\u4ee5\u76f4\u63a5\u8dd1\u6df1\u5ea6\u5b66\u4e60\uff0c\u4f46\u662f\u662f A \u5361\uff0c\u53ef\u80fd\u9700\u8981\u8e29\u5751\u3002\u7b49\u5230 CoreML \u80fd\u8bad\u7ec3\u6a21\u578b\u7684\u65f6\u5019\uff0c\u6216\u8bb8\u53ef\u4ee5\u4e70\u4e00\u4e2a\u8bd5\u8bd5\u770b\u3002","title":"Mac Pro"},{"location":"mac-compare/#_1","text":"\u5b66\u751f\u515a\u6309\u9884\u7b97\u9009\u62e9\u4e70\u5f97\u8d77\u7684\u6700\u597d\u7684 MacBook Pro\uff0c\u6709\u56fa\u5b9a\u5de5\u4f4d\u7684\u5b66\u751f\u6216\u4e0a\u73ed\u65cf\u53ef\u4ee5\u8003\u8651\u4e70 iMac \u6216\u8005 Mac mini\uff0c\u8ffd\u6c42\u8f7b\u4fbf\u53ef\u4ee5\u9009 MacBook\u3002 \u6700\u4f73\u642d\u914d\u662f\u5bb6\u91cc\u653e\u4e00\u53f0 iMac\uff0c\u51fa\u95e8\u4f7f\u7528 MacBook\uff0c\u4f7f\u7528 iCloud \u8fdb\u884c\u8bbe\u5907\u4e4b\u95f4\u7684\u6587\u4ef6\u540c\u6b65\u3002","title":"\u603b\u7ed3"},{"location":"macos-environment/","text":"macOS \u73af\u5883 \u8fd9\u7bc7\u6587\u7ae0\u4f1a\u4ecb\u7ecd\u6211\u5728 macOS \u7684\u7ec8\u7aef\u91cc\u5b89\u88c5\u7684\u547d\u4ee4\u548c\u8f6f\u4ef6\u3002 \u811a\u672c\u5f0f\u88c5\u673a\uff1a # \u6dfb\u52a0\u4ee3\u7406 export https_proxy = your_proxy_address # \u5b89\u88c5 brew\uff0c\u9700\u8981\u624b\u52a8\u8f93\u5165\u5bc6\u7801\uff0c\u6309\u56de\u8f66 /bin/bash -c \" $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh ) \" # \u6dfb\u52a0\u73af\u5883\u53d8\u91cf echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' >> /Users/ypw/.zprofile eval \" $( /opt/homebrew/bin/brew shellenv ) \" # \u5b89\u88c5\u5e38\u7528\u547d\u4ee4 brew install aria2 cmake curl pv htop nano nload nmap p7zip tree wget watch # \u5b89\u88c5 Oh-my-zsh sh -c \" $( curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \" # \u5b89\u88c5 iTerm2 brew install --cask iterm2 # \u5b89\u88c5\u4e00\u4e9b\u5fc5\u5907\u8f6f\u4ef6 brew install --cask 1password baidunetdisk caffeine clash-for-windows dingtalk github google-chrome iina hex-fiend istat-menus karabiner-elements netron postman pycharm qbittorrent qq sublime-text macdown tinypng4mac typora visual-studio-code wechat wechatwork xquartz # Clash \u89e3\u51b3\u5df2\u635f\u574f\u95ee\u9898 sudo xattr -r -d com.apple.quarantine /Applications/Clash \\ for \\ Windows.app # \u5b89\u88c5Chrome open https://www.google.cn/chrome/ # \u5b89\u88c5\u641c\u72d7\u8f93\u5165\u6cd5 open https://pinyin.sogou.com/mac/ # \u5b89\u88c5 Python x86 \uff08\u53ef\u9009\uff09 sudo softwareupdate --install-rosetta --agree-to-license wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-x86_64.sh bash Miniconda3-latest-MacOSX-x86_64.sh -b # \u5b89\u88c5 Python arm64 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-arm64.sh bash Miniconda3-latest-MacOSX-arm64.sh -b # \u5b89\u88c5 Python \u73af\u5883 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm tensorboardx torch torchvision xlrd openpyxl openmim mim install mmdet Homebrew \u5b89\u88c5 Homebrew \u4e4b\u524d\uff0c\u5efa\u8bae\u5148\u901a\u8fc7 App Store \u5b89\u88c5 Xcode \u5e76\u63a5\u53d7 \u300cXcode and Apple SDKs Agreement\u300d\uff0c\u4e0d\u7136\u5c31\u9700\u8981\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u63a5\u53d7\u534f\u8bae\u3002 Homebrew \u662f macOS \u4e0a\u7684\u4e00\u4e2a\u5305\u7ba1\u7406\u5668\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 Homebrew \u5b89\u88c5 Apple \u6ca1\u6709\u9884\u88c5\u4f46 \u4f60\u9700\u8981\u7684\u4e1c\u897f \u3002 \u5b89\u88c5 Homebrew \u53ea\u9700\u8981\u4e00\u884c\u547d\u4ee4\uff1a /bin/bash -c \" $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh ) \" \u5728\u7ec8\u7aef\u4e2d\u8fd0\u884c\u4ee5\u4e0b\u4e24\u4e2a\u547d\u4ee4\uff0c\u5c06 Homebrew \u6dfb\u52a0\u5230\u4f60\u7684\u73af\u5883\u53d8\u91cf PATH \u4e2d\uff1a ( echo ; echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' ) >> /Users/lhy/.zprofile eval \" $( /opt/homebrew/bin/brew shellenv ) \" \u8fd9\u91cc\u7684 lhy \u662f\u7528\u6237\u6587\u4ef6\u5939\uff0c\u6240\u4ee5\u4e0d\u8981\u76f4\u63a5\u590d\u5236\u8fd9\u91cc\u7684\u547d\u4ee4\uff0cHomebrew \u5b89\u88c5\u5b8c\u6210\u540e\u4f1a\u63d0\u793a\u4f60\u9700\u8981\u4f7f\u7528\u7684\u547d\u4ee4\u3002 \u901a\u8fc7 brew --version \u6d4b\u8bd5 Homebrew \u662f\u5426\u5b89\u88c5\u6210\u529f\uff1a brew --version \u4f7f\u7528 Homebrew \u5b89\u88c5\u4e00\u4e2a wget \u5427\uff1a brew install wget \u5f53\u4f60\u9700\u8981\u66f4\u65b0\u7684\u65f6\u5019\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5b8c\u6210\uff1a brew update && brew upgrade && brew cleanup \u8fd9\u662f\u4e00\u6761\u7ec8\u7aef\u547d\u4ee4\uff0c\u7528\u4e8e\u66f4\u65b0\u548c\u5347\u7ea7 Homebrew\uff0c\u540c\u65f6\u6e05\u7406\u8fc7\u671f\u7684\u5305\u548c\u7f13\u5b58\u3002\u5177\u4f53\u89e3\u91ca\u5982\u4e0b\uff1a brew update \uff1a\u66f4\u65b0 Homebrew \u7684\u672c\u5730\u5305\u4fe1\u606f\uff0c\u4f7f\u5176\u4e0e\u8fdc\u7a0b\u4ed3\u5e93\u540c\u6b65\u3002 brew upgrade \uff1a\u5347\u7ea7\u5df2\u5b89\u88c5\u7684\u5305\u81f3\u6700\u65b0\u7248\u672c\u3002 brew cleanup \uff1a\u6e05\u7406\u5df2\u5b89\u88c5\u7684\u5305\u4e2d\u8fc7\u671f\u7684\u7248\u672c\u548c\u65e0\u7528\u7684\u7f13\u5b58\uff0c\u91ca\u653e\u78c1\u76d8\u7a7a\u95f4\u3002 \u8fd9\u4e09\u4e2a\u547d\u4ee4\u53ef\u4ee5\u4e00\u8d77\u4f7f\u7528\uff0c\u4ee5\u4fdd\u6301 Homebrew \u7684\u6700\u65b0\u72b6\u6001\u5e76\u6e05\u7406\u4e0d\u5fc5\u8981\u7684\u6587\u4ef6\u3002 \u5207\u6362\u6e90 \u5982\u679c\u4f60\u89c9\u5f97\u4f7f\u7528 brew \u5b89\u88c5\u548c\u66f4\u65b0\u8f6f\u4ef6\u7684\u65f6\u5019\u975e\u5e38\u6162\uff0c\u53ef\u4ee5\u4f7f\u7528\u5176\u4ed6\u7684\u955c\u50cf\uff0c\u5982 \u6e05\u534e\u5927\u5b66 \uff1a \u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u53ef\u4ee5\u52a0\u901f brew update \uff1a git -C \" $( brew --repo ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git git -C \" $( brew --repo homebrew/core ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git git -C \" $( brew --repo homebrew/cask ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git brew update \u8bbe\u7f6e\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u53ef\u4ee5\u52a0\u901f brew install \uff1a export HOMEBREW_BOTTLE_DOMAIN = https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles Zsh \u548c Oh My Zsh \u7ec8\u7aef\u8f6f\u4ef6\u5b89\u88c5\u4ee5\u540e\uff0c\u6211\u4eec\u8fd8\u9700\u8981\u5b89\u88c5\u4e00\u4e2a\u597d\u7528\u7684 shell \u89e3\u91ca\u5668\uff0czsh \u548c oh my zsh\u3002 \u5b83\u6bd4\u9ed8\u8ba4\u7684 bash \u6709\u4ee5\u4e0b\u51e0\u4e2a\u4f18\u70b9\uff1a \u5f53\u4f60\u4f7f\u7528 tab \u63d0\u793a\u7684\u65f6\u5019\uff0c\u5982\u679c\u6709\u591a\u4e2a\u5339\u914d\u9879\uff0c\u4f60\u53ef\u4ee5\u7528 tab \u8fdb\u884c\u5207\u6362 \u5f53\u4f60\u60f3\u4f7f\u7528\u4e00\u4e2a\u4e4b\u524d\u8f93\u5165\u8fc7\u7684\u547d\u4ee4\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u8f93\u5165\u9996\u5b57\u6bcd\uff0c\u7136\u540e\u6309\u4e0a\u65b9\u5411\u952e\u5207\u6362 \u5728 macOS \u4e0b\u5b89\u88c5 oh my zsh \u5728 macOS \u4e0b\uff0c\u9996\u5148\u9700\u8981\u5b89\u88c5 zsh\uff0c\u7136\u540e\u518d\u5b89\u88c5 oh my zsh\u3002 \u5b89\u88c5\u6b65\u9aa4\u5982\u4e0b\uff1a \u5b89\u88c5 zsh \u5b89\u88c5 oh my zsh \u5b8c\u6574\u547d\u4ee4\u5982\u4e0b\uff1a # \u5b89\u88c5 zsh brew install zsh zsh-completions # \u5b89\u88c5 oh my zsh sh -c \" $( curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \" \u6700\u540e\u9700\u8981\u8f93\u5165\u4e00\u6b21\u5bc6\u7801\uff0c\u8bb0\u5f97\u8f93\u5165\u6b63\u786e\uff0c\u5426\u5219\u4e0b\u4e00\u6b21\u542f\u52a8\u7ec8\u7aef\u5c31\u4e0d\u4f1a\u4f7f\u7528 zsh\u3002\u5982\u679c\u4f60\u4e0d\u5c0f\u5fc3\u9519\u8fc7\u4e86\uff0c\u53ef\u4ee5\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u624b\u52a8\u5207\u6362\u9ed8\u8ba4\u7ec8\u7aef\uff1a chsh -s /bin/zsh \u68c0\u67e5 zsh \u662f\u5426\u5b89\u88c5\u6210\u529f\uff1a echo $SHELL \u5982\u679c\u8f93\u51fa\u7ed3\u679c\u4e3a /bin/zsh \uff0c\u5219\u8868\u793a\u4f60\u6b63\u5728\u4f7f\u7528 zsh\u3002 \u5fc5\u5907\u8f6f\u4ef6 \u4f7f\u7528 homebrew-cask \u53ef\u4ee5\u8f7b\u677e\u5b89\u88c5\u5404\u79cd macOS \u8f6f\u4ef6\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u53ef\u4ee5\u5b89\u88c5\u4e00\u4e9b\u5fc5\u5907\u8f6f\u4ef6\uff1a \u7ec8\u7aef brew install --cask iTerm2 \u7f16\u8f91\u5668 brew install --cask Sublime-Text MacDown Typora Hex-Fiend \u6d4f\u89c8\u5668 brew install --cask Google-Chrome \u5f00\u53d1\u8f6f\u4ef6 brew install --cask PyCharm miniconda GitHub Postman \u5b9e\u7528\u5de5\u5177 brew install --cask Netron Karabiner-Elements The-Unarchiver Caffeine \u65e5\u5e38\u5e94\u7528 brew install --cask WeChat QQ IINA BaiduNetdisk \u5fc5\u5907\u547d\u4ee4 brew install git htop nload wget git git \u662f\u4ee3\u7801\u7ba1\u7406\u5de5\u5177\u3002 htop htop \u662f\u4e00\u4e2a\u7cfb\u7edf\u76d1\u63a7\u4e0e\u8fdb\u7a0b\u7ba1\u7406\u8f6f\u4ef6\uff0c \u5982\uff1a nload nload \u662f\u4e00\u4e2a\u7f51\u901f\u76d1\u63a7\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u7528\u5b83\u67e5\u770b\u6bd4\u5982\u6253\u5305 docker \u7684\u65f6\u5019\u7684\u7f51\u901f\u5982\u4f55\uff0c\u662f\u5426\u5728\u4e0b\u8f7d\u4f9d\u8d56\u7684\u8f6f\u4ef6\u5305\u3002 \u4e0b\u9762\u662f\u8fd0\u884c https://www.speedtest.net \u7684\u65f6\u5019\u76d1\u63a7 nload \u7684\u8fc7\u7a0b\uff1a wget \u5f88\u65b9\u4fbf\u7684\u547d\u4ee4\u884c\u4e0b\u8f7d\u5de5\u5177\uff0c\u6bd4\u5982\uff1a wget https://repo.anaconda.com/archive/Anaconda3-2019.03-MacOSX-x86_64.sh bash Anaconda3-2019.03-MacOSX-x86_64.sh \u901a\u8fc7\u4e0a\u9762\u7684\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u4e0b\u8f7d Anaconda \u5b89\u88c5\u5305\uff0c\u7136\u540e\u5b89\u88c5 Anaconda\u3002 \u901a\u8fc7 -c \u53c2\u6570\uff0c\u53ef\u4ee5\u63a5\u7740\u4e0a\u6b21\u7684\u8fdb\u5ea6\u7ee7\u7eed\u4e0b\u8f7d\u3002 \u5982\uff1a","title":"macOS \u73af\u5883"},{"location":"macos-environment/#macos","text":"\u8fd9\u7bc7\u6587\u7ae0\u4f1a\u4ecb\u7ecd\u6211\u5728 macOS \u7684\u7ec8\u7aef\u91cc\u5b89\u88c5\u7684\u547d\u4ee4\u548c\u8f6f\u4ef6\u3002 \u811a\u672c\u5f0f\u88c5\u673a\uff1a # \u6dfb\u52a0\u4ee3\u7406 export https_proxy = your_proxy_address # \u5b89\u88c5 brew\uff0c\u9700\u8981\u624b\u52a8\u8f93\u5165\u5bc6\u7801\uff0c\u6309\u56de\u8f66 /bin/bash -c \" $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh ) \" # \u6dfb\u52a0\u73af\u5883\u53d8\u91cf echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' >> /Users/ypw/.zprofile eval \" $( /opt/homebrew/bin/brew shellenv ) \" # \u5b89\u88c5\u5e38\u7528\u547d\u4ee4 brew install aria2 cmake curl pv htop nano nload nmap p7zip tree wget watch # \u5b89\u88c5 Oh-my-zsh sh -c \" $( curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \" # \u5b89\u88c5 iTerm2 brew install --cask iterm2 # \u5b89\u88c5\u4e00\u4e9b\u5fc5\u5907\u8f6f\u4ef6 brew install --cask 1password baidunetdisk caffeine clash-for-windows dingtalk github google-chrome iina hex-fiend istat-menus karabiner-elements netron postman pycharm qbittorrent qq sublime-text macdown tinypng4mac typora visual-studio-code wechat wechatwork xquartz # Clash \u89e3\u51b3\u5df2\u635f\u574f\u95ee\u9898 sudo xattr -r -d com.apple.quarantine /Applications/Clash \\ for \\ Windows.app # \u5b89\u88c5Chrome open https://www.google.cn/chrome/ # \u5b89\u88c5\u641c\u72d7\u8f93\u5165\u6cd5 open https://pinyin.sogou.com/mac/ # \u5b89\u88c5 Python x86 \uff08\u53ef\u9009\uff09 sudo softwareupdate --install-rosetta --agree-to-license wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-x86_64.sh bash Miniconda3-latest-MacOSX-x86_64.sh -b # \u5b89\u88c5 Python arm64 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-MacOSX-arm64.sh bash Miniconda3-latest-MacOSX-arm64.sh -b # \u5b89\u88c5 Python \u73af\u5883 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm tensorboardx torch torchvision xlrd openpyxl openmim mim install mmdet","title":"macOS \u73af\u5883"},{"location":"macos-environment/#homebrew","text":"\u5b89\u88c5 Homebrew \u4e4b\u524d\uff0c\u5efa\u8bae\u5148\u901a\u8fc7 App Store \u5b89\u88c5 Xcode \u5e76\u63a5\u53d7 \u300cXcode and Apple SDKs Agreement\u300d\uff0c\u4e0d\u7136\u5c31\u9700\u8981\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u63a5\u53d7\u534f\u8bae\u3002 Homebrew \u662f macOS \u4e0a\u7684\u4e00\u4e2a\u5305\u7ba1\u7406\u5668\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 Homebrew \u5b89\u88c5 Apple \u6ca1\u6709\u9884\u88c5\u4f46 \u4f60\u9700\u8981\u7684\u4e1c\u897f \u3002 \u5b89\u88c5 Homebrew \u53ea\u9700\u8981\u4e00\u884c\u547d\u4ee4\uff1a /bin/bash -c \" $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh ) \" \u5728\u7ec8\u7aef\u4e2d\u8fd0\u884c\u4ee5\u4e0b\u4e24\u4e2a\u547d\u4ee4\uff0c\u5c06 Homebrew \u6dfb\u52a0\u5230\u4f60\u7684\u73af\u5883\u53d8\u91cf PATH \u4e2d\uff1a ( echo ; echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' ) >> /Users/lhy/.zprofile eval \" $( /opt/homebrew/bin/brew shellenv ) \" \u8fd9\u91cc\u7684 lhy \u662f\u7528\u6237\u6587\u4ef6\u5939\uff0c\u6240\u4ee5\u4e0d\u8981\u76f4\u63a5\u590d\u5236\u8fd9\u91cc\u7684\u547d\u4ee4\uff0cHomebrew \u5b89\u88c5\u5b8c\u6210\u540e\u4f1a\u63d0\u793a\u4f60\u9700\u8981\u4f7f\u7528\u7684\u547d\u4ee4\u3002 \u901a\u8fc7 brew --version \u6d4b\u8bd5 Homebrew \u662f\u5426\u5b89\u88c5\u6210\u529f\uff1a brew --version \u4f7f\u7528 Homebrew \u5b89\u88c5\u4e00\u4e2a wget \u5427\uff1a brew install wget \u5f53\u4f60\u9700\u8981\u66f4\u65b0\u7684\u65f6\u5019\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5b8c\u6210\uff1a brew update && brew upgrade && brew cleanup \u8fd9\u662f\u4e00\u6761\u7ec8\u7aef\u547d\u4ee4\uff0c\u7528\u4e8e\u66f4\u65b0\u548c\u5347\u7ea7 Homebrew\uff0c\u540c\u65f6\u6e05\u7406\u8fc7\u671f\u7684\u5305\u548c\u7f13\u5b58\u3002\u5177\u4f53\u89e3\u91ca\u5982\u4e0b\uff1a brew update \uff1a\u66f4\u65b0 Homebrew \u7684\u672c\u5730\u5305\u4fe1\u606f\uff0c\u4f7f\u5176\u4e0e\u8fdc\u7a0b\u4ed3\u5e93\u540c\u6b65\u3002 brew upgrade \uff1a\u5347\u7ea7\u5df2\u5b89\u88c5\u7684\u5305\u81f3\u6700\u65b0\u7248\u672c\u3002 brew cleanup \uff1a\u6e05\u7406\u5df2\u5b89\u88c5\u7684\u5305\u4e2d\u8fc7\u671f\u7684\u7248\u672c\u548c\u65e0\u7528\u7684\u7f13\u5b58\uff0c\u91ca\u653e\u78c1\u76d8\u7a7a\u95f4\u3002 \u8fd9\u4e09\u4e2a\u547d\u4ee4\u53ef\u4ee5\u4e00\u8d77\u4f7f\u7528\uff0c\u4ee5\u4fdd\u6301 Homebrew \u7684\u6700\u65b0\u72b6\u6001\u5e76\u6e05\u7406\u4e0d\u5fc5\u8981\u7684\u6587\u4ef6\u3002","title":"Homebrew"},{"location":"macos-environment/#_1","text":"\u5982\u679c\u4f60\u89c9\u5f97\u4f7f\u7528 brew \u5b89\u88c5\u548c\u66f4\u65b0\u8f6f\u4ef6\u7684\u65f6\u5019\u975e\u5e38\u6162\uff0c\u53ef\u4ee5\u4f7f\u7528\u5176\u4ed6\u7684\u955c\u50cf\uff0c\u5982 \u6e05\u534e\u5927\u5b66 \uff1a \u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u53ef\u4ee5\u52a0\u901f brew update \uff1a git -C \" $( brew --repo ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git git -C \" $( brew --repo homebrew/core ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git git -C \" $( brew --repo homebrew/cask ) \" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git brew update \u8bbe\u7f6e\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u53ef\u4ee5\u52a0\u901f brew install \uff1a export HOMEBREW_BOTTLE_DOMAIN = https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles","title":"\u5207\u6362\u6e90"},{"location":"macos-environment/#zsh-oh-my-zsh","text":"\u7ec8\u7aef\u8f6f\u4ef6\u5b89\u88c5\u4ee5\u540e\uff0c\u6211\u4eec\u8fd8\u9700\u8981\u5b89\u88c5\u4e00\u4e2a\u597d\u7528\u7684 shell \u89e3\u91ca\u5668\uff0czsh \u548c oh my zsh\u3002 \u5b83\u6bd4\u9ed8\u8ba4\u7684 bash \u6709\u4ee5\u4e0b\u51e0\u4e2a\u4f18\u70b9\uff1a \u5f53\u4f60\u4f7f\u7528 tab \u63d0\u793a\u7684\u65f6\u5019\uff0c\u5982\u679c\u6709\u591a\u4e2a\u5339\u914d\u9879\uff0c\u4f60\u53ef\u4ee5\u7528 tab \u8fdb\u884c\u5207\u6362 \u5f53\u4f60\u60f3\u4f7f\u7528\u4e00\u4e2a\u4e4b\u524d\u8f93\u5165\u8fc7\u7684\u547d\u4ee4\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u8f93\u5165\u9996\u5b57\u6bcd\uff0c\u7136\u540e\u6309\u4e0a\u65b9\u5411\u952e\u5207\u6362","title":"Zsh \u548c Oh My Zsh"},{"location":"macos-environment/#macos-oh-my-zsh","text":"\u5728 macOS \u4e0b\uff0c\u9996\u5148\u9700\u8981\u5b89\u88c5 zsh\uff0c\u7136\u540e\u518d\u5b89\u88c5 oh my zsh\u3002 \u5b89\u88c5\u6b65\u9aa4\u5982\u4e0b\uff1a \u5b89\u88c5 zsh \u5b89\u88c5 oh my zsh \u5b8c\u6574\u547d\u4ee4\u5982\u4e0b\uff1a # \u5b89\u88c5 zsh brew install zsh zsh-completions # \u5b89\u88c5 oh my zsh sh -c \" $( curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \" \u6700\u540e\u9700\u8981\u8f93\u5165\u4e00\u6b21\u5bc6\u7801\uff0c\u8bb0\u5f97\u8f93\u5165\u6b63\u786e\uff0c\u5426\u5219\u4e0b\u4e00\u6b21\u542f\u52a8\u7ec8\u7aef\u5c31\u4e0d\u4f1a\u4f7f\u7528 zsh\u3002\u5982\u679c\u4f60\u4e0d\u5c0f\u5fc3\u9519\u8fc7\u4e86\uff0c\u53ef\u4ee5\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u624b\u52a8\u5207\u6362\u9ed8\u8ba4\u7ec8\u7aef\uff1a chsh -s /bin/zsh \u68c0\u67e5 zsh \u662f\u5426\u5b89\u88c5\u6210\u529f\uff1a echo $SHELL \u5982\u679c\u8f93\u51fa\u7ed3\u679c\u4e3a /bin/zsh \uff0c\u5219\u8868\u793a\u4f60\u6b63\u5728\u4f7f\u7528 zsh\u3002","title":"\u5728 macOS \u4e0b\u5b89\u88c5 oh my zsh"},{"location":"macos-environment/#_2","text":"\u4f7f\u7528 homebrew-cask \u53ef\u4ee5\u8f7b\u677e\u5b89\u88c5\u5404\u79cd macOS \u8f6f\u4ef6\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u53ef\u4ee5\u5b89\u88c5\u4e00\u4e9b\u5fc5\u5907\u8f6f\u4ef6\uff1a","title":"\u5fc5\u5907\u8f6f\u4ef6"},{"location":"macos-environment/#_3","text":"brew install --cask iTerm2","title":"\u7ec8\u7aef"},{"location":"macos-environment/#_4","text":"brew install --cask Sublime-Text MacDown Typora Hex-Fiend","title":"\u7f16\u8f91\u5668"},{"location":"macos-environment/#_5","text":"brew install --cask Google-Chrome","title":"\u6d4f\u89c8\u5668"},{"location":"macos-environment/#_6","text":"brew install --cask PyCharm miniconda GitHub Postman","title":"\u5f00\u53d1\u8f6f\u4ef6"},{"location":"macos-environment/#_7","text":"brew install --cask Netron Karabiner-Elements The-Unarchiver Caffeine","title":"\u5b9e\u7528\u5de5\u5177"},{"location":"macos-environment/#_8","text":"brew install --cask WeChat QQ IINA BaiduNetdisk","title":"\u65e5\u5e38\u5e94\u7528"},{"location":"macos-environment/#_9","text":"brew install git htop nload wget","title":"\u5fc5\u5907\u547d\u4ee4"},{"location":"macos-environment/#git","text":"git \u662f\u4ee3\u7801\u7ba1\u7406\u5de5\u5177\u3002","title":"git"},{"location":"macos-environment/#htop","text":"htop \u662f\u4e00\u4e2a\u7cfb\u7edf\u76d1\u63a7\u4e0e\u8fdb\u7a0b\u7ba1\u7406\u8f6f\u4ef6\uff0c \u5982\uff1a","title":"htop"},{"location":"macos-environment/#nload","text":"nload \u662f\u4e00\u4e2a\u7f51\u901f\u76d1\u63a7\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u7528\u5b83\u67e5\u770b\u6bd4\u5982\u6253\u5305 docker \u7684\u65f6\u5019\u7684\u7f51\u901f\u5982\u4f55\uff0c\u662f\u5426\u5728\u4e0b\u8f7d\u4f9d\u8d56\u7684\u8f6f\u4ef6\u5305\u3002 \u4e0b\u9762\u662f\u8fd0\u884c https://www.speedtest.net \u7684\u65f6\u5019\u76d1\u63a7 nload \u7684\u8fc7\u7a0b\uff1a","title":"nload"},{"location":"macos-environment/#wget","text":"\u5f88\u65b9\u4fbf\u7684\u547d\u4ee4\u884c\u4e0b\u8f7d\u5de5\u5177\uff0c\u6bd4\u5982\uff1a wget https://repo.anaconda.com/archive/Anaconda3-2019.03-MacOSX-x86_64.sh bash Anaconda3-2019.03-MacOSX-x86_64.sh \u901a\u8fc7\u4e0a\u9762\u7684\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u4e0b\u8f7d Anaconda \u5b89\u88c5\u5305\uff0c\u7136\u540e\u5b89\u88c5 Anaconda\u3002 \u901a\u8fc7 -c \u53c2\u6570\uff0c\u53ef\u4ee5\u63a5\u7740\u4e0a\u6b21\u7684\u8fdb\u5ea6\u7ee7\u7eed\u4e0b\u8f7d\u3002 \u5982\uff1a","title":"wget"},{"location":"macos-software/","text":"macOS \u8f6f\u4ef6 \u4e0b\u9762\u662f\u6211\u5b89\u88c5\u7684\u4e0e\u5de5\u4f5c\u6709\u5173\u7684\u8f6f\u4ef6\u3002 \u672c\u7bc7\u6587\u7ae0\u4f1a\u4ecb\u7ecd\u8fd9\u4e9b\u8f6f\u4ef6\u7684\u4f5c\u7528\uff0c\u5927\u90e8\u5206\u8f6f\u4ef6\u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4\u76f4\u63a5\u5b89\u88c5\uff0c\u53c2\u8003 macOS \u73af\u5883-\u5fc5\u5907\u8f6f\u4ef6 \u3002 \u7ec8\u7aef iTerm2 \u7ec8\u7aef\u9996\u9009 iTerm\uff0c\u6700\u5927\u7684\u597d\u5904\u662f\u53ef\u4ee5\u7ed3\u5408 tmux \u5206\u5c4f\u4f7f\u7528\uff0c\u6bd4\u5982\uff1a \u5feb\u6377\u952e\u914d\u7f6e \u5f00\u542f \u2318\u2190, \u2318\u2192 \u548c \u2325\u2190, \u2325\u2192 \u5feb\u6377\u952e\uff0c\u53ef\u4ee5\u76f4\u63a5\u8df3\u5230\u884c\u9996\uff0c\u4ee5\u53ca\u8df3\u8fc7\u5355\u8bcd\uff0c\u5728\u8f93\u5165\u5f88\u957f\u7684\u547d\u4ee4\u7684\u65f6\u5019\u5f88\u6709\u7528\u3002 \u9996\u5148\u6253\u5f00 iTerm2 \u7684\u504f\u597d\u8bbe\u7f6e\uff08Preferences\uff09\uff0c\u7136\u540e\u5207\u6362\u5230 Profiles\uff0c\u5728\u53f3\u8fb9\u627e\u5230 Keys \u5feb\u6377\u952e\u914d\u7f6e\uff1a \u70b9\u51fb Key Mappings \u4e0b\u9762\u7684\u52a0\u53f7\uff08+\uff09\uff0c\u6309\u4e0b\u9762\u7684\u8868\u683c\u6dfb\u52a0\u5feb\u6377\u952e\uff1a Keyboard Shortcut Action Esc+ \u2318\u2190 Send Escape Sequence OH \u2318\u2192 Send Escape Sequence OF \u2325\u2190 Send Escape Sequenceb b \u2325\u2192 Send Escape Sequencef f \u5982\u56fe\uff1a \u5982\u679c\u5f39\u51fa Warning\uff0c\u76f4\u63a5\u70b9\u786e\u5b9a\u5373\u53ef\u3002\u5982\u679c\u70b9\u4e86\u786e\u5b9a\u6ca1\u53cd\u5e94\uff0c\u4e0d\u7528\u7ba1\u5b83\uff0c\u7ee7\u7eed\u628a\u914d\u7f6e\u52a0\u5b8c\uff0c\u7136\u540e\u91cd\u65b0\u5f00\u542f\u8f6f\u4ef6\u5c31\u884c\u3002 \u5173\u95ed\u9ed8\u8ba4\u975e\u6d3b\u8dc3\u7a97\u53e3\u53d8\u7070\u7684\u9009\u9879 \u53d6\u6d88\u52fe\u9009 Preferences -> Appearance -> Dim inactive split panes \u5373\u53ef\u3002 \u7f16\u8f91\u5668 Sublime Text Sublime Text \u662f\u4e00\u4e2a\u975e\u5e38\u8f7b\u91cf\u5316\u7684\u6587\u672c\u7f16\u8f91\u5668\uff0c\u542f\u52a8\u8fc5\u901f\uff0c\u652f\u6301\u5404\u79cd\u8bed\u8a00\u7684\u4ee3\u7801\u9ad8\u4eae\u3002 \u5f53\u4f60\u53ea\u60f3\u6253\u5f00\u5e9e\u5927\u5de5\u7a0b\u91cc\u7684\u4e00\u4e2a\u6587\u4ef6\u7684\u65f6\u5019\uff0c\u4f60\u5c31\u53ef\u4ee5\u7528\u5b83\u6765\u9605\u8bfb\u548c\u4fee\u6539\u4ee3\u7801\u3002 MacDown MacDown \u662f\u4e00\u4e2a markdown \u7f16\u8f91\u5668\uff0c\u652f\u6301 Markdown \u4ee5\u53ca LaTeX\uff0c\u5199\u6587\u7ae0\u5fc5\u5907\u3002 Typora \u53e6\u4e00\u4e2a Markdown \u7f16\u8f91\u5668\uff0c\u4e0e MacDown \u4e0d\u540c\u5728\u4e8e\uff0cMacDown \u662f\u5206\u680f\u7f16\u8f91\uff0c\u5de6\u8fb9 Markdown\uff0c\u53f3\u8fb9\u5b9e\u65f6\u6e32\u67d3\uff0c\u800c Typora \u53ea\u6709\u4e00\u4e2a\u7f16\u8f91\u754c\u9762\uff0c\u5b9e\u65f6\u5199\u5b9e\u65f6\u6e32\u67d3\u3002 Hex Fiend Hex Fiend \u662f\u4e00\u4e2a\u5341\u516d\u8fdb\u5236\u7f16\u8f91\u5668\uff0c\u5f53\u4f60\u60f3\u67e5\u770b\u4e00\u4e2a\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u7684\u65f6\u5019\u5c31\u53ef\u4ee5\u4f7f\u7528\u5b83\uff0c\u6bd4\u5982\u6211\u4f1a\u7528\u5b83\u6765\u68c0\u67e5\u6211\u5199\u51fa\u7684\u6a21\u578b\u6743\u503c\u6587\u4ef6\u3002\u56e0\u4e3a\u5b83\u53ef\u4ee5\u79d2\u5f00\u4efb\u4f55\u5927\u5c0f\u7684\u6587\u4ef6\uff0c\u6709\u65f6\u5019\u6211\u4e5f\u4f1a\u7528\u5b83\u6765\u67e5\u770b\u51e0\u767e\u5146\u7684\u6587\u672c\u6587\u4ef6\u3002 \u6d4f\u89c8\u5668 Chrome Chrome \u63d2\u4ef6 Chrome {% embed url=\"https://www.google.com/chrome/\" %} \u76ee\u524d Chrome \u5e94\u8be5\u662f\u6700\u53d7\u6b22\u8fce\u7684\u6d4f\u89c8\u5668\uff1a \u8fd9\u91cc\u5efa\u8bae\u4f7f\u7528 Chrome \u4f5c\u4e3a\u4e3b\u529b\u6d4f\u89c8\u5668\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u7b80\u6d01 \u63d2\u4ef6\u5f3a\u5927\u4e14\u514d\u8d39\uff08Safari \u7684\u67d0\u4e9b\u63d2\u4ef6\u662f\u6536\u8d39\u7684\uff09 \u5e38\u7528\u63d2\u4ef6 Adblock Plus \u62e6\u622a\u5e7f\u544a\u7684\u597d\u5de5\u5177\u3002 Tampermonkey \u811a\u672c\u7ba1\u7406\u5668\uff0c\u4f60\u53ef\u4ee5\u627e\u5230\u652f\u6301\u5404\u79cd\u529f\u80fd\u7684\u811a\u672c\uff0c\u6bd4\u5982\uff1a \u53bb\u5e7f\u544a \u4e0b\u8f7d\u89c6\u9891 \u4f60\u53ef\u4ee5\u81ea\u5df1\u5199 js \u811a\u672c\u4ee5\u5b9e\u73b0\u4e00\u5207\u529f\u80fd Proxy SwitchyOmega \u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u5207\u6362\u4ee3\u7406\u670d\u52a1\u5668\u3002 Octotree \u53ef\u4ee5\u5728 GitHub \u9875\u9762\u5c55\u793a\u4ee3\u7801\u6587\u4ef6\u7ed3\u6784\uff0c\u975e\u5e38\u65b9\u4fbf\uff0c\u5982\u56fe\uff1a \u5f00\u53d1\u8f6f\u4ef6 Xcode Xcode \u662f macOS \u4e0a\u7684 IDE\uff0c\u53ef\u4ee5\u5f00\u53d1 macOS\u3001iPhone\u3001iPad\u3001AppleWatch \u7b49\u5e73\u53f0\u4e0a\u7684\u5e94\u7528\uff0c\u5982\u679c\u4f60\u5e0c\u671b\u5728 iPhone \u8fdb\u884c\u8c03\u8bd5\uff0c\u4f60\u8fd8\u9700\u8981\u8d2d\u4e70 99$ \u7684\u5f00\u53d1\u8005\u8bc1\u4e66\u3002\u6211\u4eec\u4e00\u822c\u4ece AppStore \u4e0a\u4e0b\u8f7d Xcode\u3002 PyCharm PyCharm \u662f\u6211\u7ecf\u5e38\u4f7f\u7528\u7684 Python IDE\uff0c\u5b83\u652f\u6301\u4ee3\u7801\u9ad8\u4eae\u3001\u4ee3\u7801\u63d0\u793a\u3001\u8c03\u8bd5\u65ad\u70b9\u7b49\u529f\u80fd\uff0c\u4e13\u4e1a\u7248\u8fd8\u652f\u6301\u8fdc\u7a0b\u8c03\u8bd5\uff0c\u975e\u5e38\u9002\u5408\u6df1\u5ea6\u5b66\u4e60\u4ece\u4e1a\u4eba\u5458\u4f7f\u7528\u3002 \u56e0\u4e3a\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u90fd\u4e0d\u662f\u76f4\u63a5\u5728\u8bad\u7ec3\u673a\u5668\u4e0a\u5199\u4ee3\u7801\uff0c\u800c\u662f\u4f7f\u7528\u4e00\u4e2a\u7ec8\u7aef\u673a\u5668\u8fdc\u7a0b ssh \u8fdb\u884c\u4ee3\u7801\u8c03\u8bd5\u3002\u90a3\u4e48\u5982\u679c\u6bcf\u6b21\u90fd\u662f\u4e0a\u4f20\u4ee3\u7801\u3001\u8fd0\u884c Python \u811a\u672c\u3001\u770b\u62a5\u9519\uff0c\u90a3\u4e48\u5c31\u4f1a\u975e\u5e38\u4f4e\u6548\uff0c\u56e0\u4e3a\u6709\u53ef\u80fd\u4f60\u8f7d\u5165\u4e86\u4e94\u5206\u949f\u7684\u6570\u636e\u96c6\u4ee5\u540e\uff0c\u62a5\u9519\u6a21\u578b\u7684\u67d0\u4e2a\u5c42\u5199\u9519\u4e86\uff0c\u7136\u540e\u68c0\u67e5\u534a\u5929\uff0c\u4e0a\u4f20\u4e00\u4e2a\u65b0\u7684\u4ee3\u7801\uff0c\u7136\u540e\u9677\u5165\u4e0a\u9762\u7684\u5faa\u73af\u3002 \u9ad8\u6548\u4e00\u70b9\u7684\u65b9\u6cd5\u5c31\u662f\u4f7f\u7528 jupyter notebook \u8fdb\u884c\u5f00\u53d1\uff0c\u5373\u4f7f\u4ee3\u7801\u62a5\u9519\u4e86\u4e5f\u4e0d\u4f1a\u76f4\u63a5\u9000\u51fa\uff0c\u6211\u4eec\u53ef\u4ee5\u5728 jupyter notebook \u91cc\u7ee7\u7eed\u5199\u4ee3\u7801\uff0c\u76f4\u5230\u5199\u51fa\u6b63\u786e\u7684\u4ee3\u7801\u3002\u90a3\u4e48\u8fd9\u4ecd\u7136\u4e0d\u662f\u9ad8\u6548\u7684\u65b9\u6cd5\uff0c\u56e0\u4e3a\u5982\u679c\u6211\u4eec\u6709\u4e00\u4e2a\u9519\u8bef\u53d1\u751f\u5728\u6a21\u578b\u5185\u90e8\u7684 forward \u90e8\u5206\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u9700\u8981\u7528 print \u5927\u6cd5\u5728\u51fa\u9519\u4ee3\u7801\u7684\u524d\u540e\u8f93\u51fa\u77e9\u9635\u5c3a\u5bf8\u3001\u6570\u636e\u7c7b\u578b\u7b49\u5173\u952e\u6570\u636e\uff0c\u7136\u540e\u6839\u636e\u62a5\u9519\u6765\u4fee bug\u3002 \u90a3\u4e48\u5f53\u6211\u4eec\u51fa\u73b0\u8fd9\u79cd\u62a5\u9519\u7684\u65f6\u5019\uff0c\u4f7f\u7528 PyCharm \u7684\u8fdc\u7a0b\u8c03\u8bd5\u529f\u80fd\u5c31\u975e\u5e38\u65b9\u4fbf\u4e86\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u51fa\u9519\u7684\u4ee3\u7801\u524d\u9762\u4e0b\u65ad\u70b9\uff0c\u7136\u540e\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u6bcf\u4e2a\u77e9\u9635\u7684\u5c3a\u5bf8\uff0c\u6a21\u578b\u7684\u6bcf\u4e00\u5c42\u7684\u53c2\u6570\uff0c\u4e0d\u9700\u8981\u5199\u8bb8\u591a print \u53bb\u5b9e\u73b0\u6211\u4eec\u7684\u60f3\u6cd5\u3002\u5982\u679c\u4ee3\u7801\u62a5\u9519\u662f\u4e00\u4e2a\u96640\u9519\u8bef\uff0c\u4f60\u8fd8\u53ef\u4ee5\u76f4\u63a5\u5728\u53d8\u91cf\u76d1\u89c6\u5668\u91cc\u9762\u589e\u52a0\u4e00\u4e2a x.mean() \u7684\u6761\u76ee\uff0c\u7136\u540e\u5b9e\u65f6\u67e5\u770b x \u7684\u5747\u503c\uff0c\u4e0d\u9700\u8981\u91cd\u65b0\u8fd0\u884c\u4ee3\u7801\u3002 GitHub Desktop GitHub Desktop \u662f GitHub \u5b98\u65b9\u5ba2\u6237\u7aef\uff0c\u65b0\u624b\u5fc5\u5907\u3002 Postman \u4e00\u6b3e\u975e\u5e38\u597d\u7528\u7684 API \u6d4b\u8bd5\u5de5\u5177\uff0c\u5b83\u53ef\u4ee5\u6a21\u62df\u53d1\u9001 GET\u3001POST \u7b49\u8bf7\u6c42\uff0c\u652f\u6301 JSON \u8bed\u6cd5\u9ad8\u4eae\u3002 \u5b9e\u7528\u5de5\u5177 Netron Karabiner-Elements The Unarchiver iStat Menus Caffeine DaisyDisk Netron \u5b83\u662f\u4e00\u4e2a\u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784\u7684\u8f6f\u4ef6\uff0c\u652f\u6301\u7684\u6a21\u578b\u6587\u4ef6\u683c\u5f0f\u6709\uff1a ONNX ( .onnx , .pb , .pbtxt ), Keras ( .h5 , .keras ), Core ML ( .mlmodel ), Caffe2 ( predict_net.pb , predict_net.pbtxt ), MXNet ( .model , -symbol.json ) and TensorFlow Lite ( .tflite ). Netron has experimental support for Caffe ( .caffemodel , .prototxt ), PyTorch ( .pth ), Torch ( .t7 ), CNTK ( .model , .cntk ), PaddlePaddle ( __model__ ), Darknet ( .cfg ), scikit-learn ( .pkl ), TensorFlow.js ( model.json , .pb ) and TensorFlow ( .pb , .meta , .pbtxt ). Karabiner-Elements Karabiner-Elements \u662f\u4e00\u4e2a\u6539\u952e\u5de5\u5177\uff0c\u673a\u68b0\u952e\u76d8\u5fc5\u5907\u8f6f\u4ef6\u3002 \u9002\u7528\u4e8emacOS\u7684\u529f\u80fd\u5f3a\u5927\u4e14\u7a33\u5b9a\u7684\u952e\u76d8\u5b9a\u5236\u5668\u3002 \u6211\u628a\u6211\u7684\u673a\u68b0\u952e\u76d8\u7684 Command \u952e\u548c Option \u952e\u66ff\u6362\u4e86\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u50cf\u4f7f\u7528\u539f\u751f\u952e\u76d8\u4e00\u6837\u4f7f\u7528\u6211\u7684\u673a\u68b0\u952e\u76d8\u3002\u4f60\u8fd8\u53ef\u4ee5\u628a\u952e\u76d8\u4e0a\u7684 Windows \u952e\u548c Alt \u952e\u4ea4\u6362\u4f4d\u7f6e\u3002 The Unarchiver \u8fd9\u662f\u4e00\u4e2a\u89e3\u538b\u7f29\u8f6f\u4ef6\uff0c\u53ef\u4ee5\u76f4\u63a5\u5728 App Store \u4e0a\u4e0b\u8f7d\uff0c\u514d\u8d39\uff0c\u652f\u6301 zip\u3001rar\u3001tar \u7b49\u683c\u5f0f\u3002 The Unarchiver \u662f\u4e00\u6b3e\u7b80\u5355\u6613\u7528\u7684\u5c0f\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u89e3\u538b\u8bb8\u591a\u4e0d\u540c\u7c7b\u578b\u7684\u5b58\u6863\u6587\u4ef6\u3002 \u5b83\u80fd\u591f\u6253\u5f00 Zip\u3001RAR\uff08\u5305\u62ec v5\uff09\u30017-zip\u3001Tar\u3001Gzip \u548c Bzip2 \u7b49\u5e38\u89c1\u683c\u5f0f\u3002 \u5b83\u8fd8\u80fd\u6253\u5f00\u8bb8\u591a\u65e7\u683c\u5f0f\uff0c\u4f8b\u5982 StuffIt\u3001DiskDoubler\u3001LZH\u3001ARJ \u548c ARC\u3002 \u5b83\u8fd8\u80fd\u6253\u5f00\u5176\u4ed6\u5404\u79cd\u6587\u4ef6\uff0c\u4f8b\u5982 ISO \u548c BIN \u78c1\u76d8\u955c\u50cf\u3001\u90e8\u5206 Windows .EXE \u5b89\u88c5\u7a0b\u5e8f\u3002 \u8be5\u5217\u8868\u5b9e\u9645\u4e0a\u5f88\u957f - \u6709\u5173\u5b8c\u6574\u5217\u8868\uff0c\u8bf7\u67e5\u770b\u7a0b\u5e8f\u4e3b\u9875\u3002 Caffeine \u5b83\u53ef\u4ee5\u9632\u6b62\u4f60\u7684\u7535\u8111\u8fdb\u5165\u7761\u7720\uff0c\u4f60\u53ea\u9700\u8981\u5728\u72b6\u6001\u680f\u70b9\u4e00\u4e0b\u5c31\u53ef\u4ee5\u6253\u5f00\u548c\u5173\u95ed\uff0c\u6bd4\u5728\u8bbe\u7f6e\u91cc\u9762\u64cd\u4f5c\u65b9\u4fbf\u4e0d\u5c11\u3002 iStat Menus \u8fd9\u4e2a\u8f6f\u4ef6\u53ef\u4ee5\u76d1\u63a7 Mac \u7684 CPU\u3001\u5185\u5b58\u3001\u7f51\u901f\u7b49\u4fe1\u606f\u3002\u6536\u8d39\u3002 \u901a\u8fc7\u8fd9\u4e2a\u8f6f\u4ef6\uff0c\u6211\u53ef\u4ee5\u76f4\u89c2\u5730\u67e5\u770b\u6211\u8dd1\u7a0b\u5e8f\u7684\u65f6\u5019 CPU \u6709\u6ca1\u6709\u5168\u90e8\u7528\u4e0a\uff0c\u5b83\u5728\u72b6\u6001\u680f\u5e76\u4e0d\u4f1a\u5360\u7528\u592a\u591a\u7a7a\u95f4\uff0c\u4e0b\u8f7d\u4e1c\u897f\u7684\u65f6\u5019\u4e5f\u53ef\u4ee5\u76d1\u63a7\u7f51\u901f\u3002 DaisyDisk \u8fd9\u662f\u4e00\u4e2a\u975e\u5e38\u597d\u7528\u7684\u78c1\u76d8\u7a7a\u95f4\u6574\u7406\u5de5\u5177\uff0c\u4f60\u53ef\u4ee5\u68c0\u67e5\u4f60\u7684 Mac \u4e0a\u5360\u7528\u7a7a\u95f4\u8f83\u5927\u7684\u6587\u4ef6\u90fd\u5728\u54ea\u91cc\u3002\u6536\u8d39\u3002 \u865a\u62df\u673a Parallels Desktop \u8fd9\u662f\u4e00\u6b3e\u975e\u5e38\u4f18\u79c0\u7684\u865a\u62df\u673a\u8f6f\u4ef6\uff0c\u6536\u8d39\u3002 \u5b83\u521b\u65b0\u7684\u878d\u5408\u6a21\u5f0f\u53ef\u4ee5\u8ba9\u4f60\u5728 Mac \u684c\u9762\u4e0b\uff0c\u5728\u4f7f\u7528 Windows \u8f6f\u4ef6\u7684\u65f6\u5019\u611f\u89c9\u50cf\u5728\u4f7f\u7528 Mac \u539f\u751f\u7684\u8f6f\u4ef6\uff0c\u6bd4\u5982\uff1a \u540e\u9762\u7684\u7a97\u53e3\u662f Finder\uff0c\u524d\u9762\u7684\u7a97\u53e3\u662f\u4e00\u4e2a Windows \u5e94\u7528\uff0c\u4f7f\u7528 Parallels Desktop \u53ef\u4ee5\u8ba9\u4f60\u65e0\u7f1d\u4f7f\u7528 Mac \u548c Windows \u7684\u5e94\u7528\u3002","title":"macOS \u8f6f\u4ef6"},{"location":"macos-software/#macos","text":"\u4e0b\u9762\u662f\u6211\u5b89\u88c5\u7684\u4e0e\u5de5\u4f5c\u6709\u5173\u7684\u8f6f\u4ef6\u3002 \u672c\u7bc7\u6587\u7ae0\u4f1a\u4ecb\u7ecd\u8fd9\u4e9b\u8f6f\u4ef6\u7684\u4f5c\u7528\uff0c\u5927\u90e8\u5206\u8f6f\u4ef6\u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4\u76f4\u63a5\u5b89\u88c5\uff0c\u53c2\u8003 macOS \u73af\u5883-\u5fc5\u5907\u8f6f\u4ef6 \u3002","title":"macOS \u8f6f\u4ef6"},{"location":"macos-software/#_1","text":"","title":"\u7ec8\u7aef"},{"location":"macos-software/#iterm2","text":"\u7ec8\u7aef\u9996\u9009 iTerm\uff0c\u6700\u5927\u7684\u597d\u5904\u662f\u53ef\u4ee5\u7ed3\u5408 tmux \u5206\u5c4f\u4f7f\u7528\uff0c\u6bd4\u5982\uff1a","title":"iTerm2"},{"location":"macos-software/#_2","text":"\u5f00\u542f \u2318\u2190, \u2318\u2192 \u548c \u2325\u2190, \u2325\u2192 \u5feb\u6377\u952e\uff0c\u53ef\u4ee5\u76f4\u63a5\u8df3\u5230\u884c\u9996\uff0c\u4ee5\u53ca\u8df3\u8fc7\u5355\u8bcd\uff0c\u5728\u8f93\u5165\u5f88\u957f\u7684\u547d\u4ee4\u7684\u65f6\u5019\u5f88\u6709\u7528\u3002 \u9996\u5148\u6253\u5f00 iTerm2 \u7684\u504f\u597d\u8bbe\u7f6e\uff08Preferences\uff09\uff0c\u7136\u540e\u5207\u6362\u5230 Profiles\uff0c\u5728\u53f3\u8fb9\u627e\u5230 Keys \u5feb\u6377\u952e\u914d\u7f6e\uff1a \u70b9\u51fb Key Mappings \u4e0b\u9762\u7684\u52a0\u53f7\uff08+\uff09\uff0c\u6309\u4e0b\u9762\u7684\u8868\u683c\u6dfb\u52a0\u5feb\u6377\u952e\uff1a Keyboard Shortcut Action Esc+ \u2318\u2190 Send Escape Sequence OH \u2318\u2192 Send Escape Sequence OF \u2325\u2190 Send Escape Sequenceb b \u2325\u2192 Send Escape Sequencef f \u5982\u56fe\uff1a \u5982\u679c\u5f39\u51fa Warning\uff0c\u76f4\u63a5\u70b9\u786e\u5b9a\u5373\u53ef\u3002\u5982\u679c\u70b9\u4e86\u786e\u5b9a\u6ca1\u53cd\u5e94\uff0c\u4e0d\u7528\u7ba1\u5b83\uff0c\u7ee7\u7eed\u628a\u914d\u7f6e\u52a0\u5b8c\uff0c\u7136\u540e\u91cd\u65b0\u5f00\u542f\u8f6f\u4ef6\u5c31\u884c\u3002","title":"\u5feb\u6377\u952e\u914d\u7f6e"},{"location":"macos-software/#_3","text":"\u53d6\u6d88\u52fe\u9009 Preferences -> Appearance -> Dim inactive split panes \u5373\u53ef\u3002","title":"\u5173\u95ed\u9ed8\u8ba4\u975e\u6d3b\u8dc3\u7a97\u53e3\u53d8\u7070\u7684\u9009\u9879"},{"location":"macos-software/#_4","text":"","title":"\u7f16\u8f91\u5668"},{"location":"macos-software/#sublime-text","text":"Sublime Text \u662f\u4e00\u4e2a\u975e\u5e38\u8f7b\u91cf\u5316\u7684\u6587\u672c\u7f16\u8f91\u5668\uff0c\u542f\u52a8\u8fc5\u901f\uff0c\u652f\u6301\u5404\u79cd\u8bed\u8a00\u7684\u4ee3\u7801\u9ad8\u4eae\u3002 \u5f53\u4f60\u53ea\u60f3\u6253\u5f00\u5e9e\u5927\u5de5\u7a0b\u91cc\u7684\u4e00\u4e2a\u6587\u4ef6\u7684\u65f6\u5019\uff0c\u4f60\u5c31\u53ef\u4ee5\u7528\u5b83\u6765\u9605\u8bfb\u548c\u4fee\u6539\u4ee3\u7801\u3002","title":"Sublime Text"},{"location":"macos-software/#macdown","text":"MacDown \u662f\u4e00\u4e2a markdown \u7f16\u8f91\u5668\uff0c\u652f\u6301 Markdown \u4ee5\u53ca LaTeX\uff0c\u5199\u6587\u7ae0\u5fc5\u5907\u3002","title":"MacDown"},{"location":"macos-software/#typora","text":"\u53e6\u4e00\u4e2a Markdown \u7f16\u8f91\u5668\uff0c\u4e0e MacDown \u4e0d\u540c\u5728\u4e8e\uff0cMacDown \u662f\u5206\u680f\u7f16\u8f91\uff0c\u5de6\u8fb9 Markdown\uff0c\u53f3\u8fb9\u5b9e\u65f6\u6e32\u67d3\uff0c\u800c Typora \u53ea\u6709\u4e00\u4e2a\u7f16\u8f91\u754c\u9762\uff0c\u5b9e\u65f6\u5199\u5b9e\u65f6\u6e32\u67d3\u3002","title":"Typora"},{"location":"macos-software/#hex-fiend","text":"Hex Fiend \u662f\u4e00\u4e2a\u5341\u516d\u8fdb\u5236\u7f16\u8f91\u5668\uff0c\u5f53\u4f60\u60f3\u67e5\u770b\u4e00\u4e2a\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u7684\u65f6\u5019\u5c31\u53ef\u4ee5\u4f7f\u7528\u5b83\uff0c\u6bd4\u5982\u6211\u4f1a\u7528\u5b83\u6765\u68c0\u67e5\u6211\u5199\u51fa\u7684\u6a21\u578b\u6743\u503c\u6587\u4ef6\u3002\u56e0\u4e3a\u5b83\u53ef\u4ee5\u79d2\u5f00\u4efb\u4f55\u5927\u5c0f\u7684\u6587\u4ef6\uff0c\u6709\u65f6\u5019\u6211\u4e5f\u4f1a\u7528\u5b83\u6765\u67e5\u770b\u51e0\u767e\u5146\u7684\u6587\u672c\u6587\u4ef6\u3002","title":"Hex Fiend"},{"location":"macos-software/#_5","text":"Chrome Chrome \u63d2\u4ef6","title":"\u6d4f\u89c8\u5668"},{"location":"macos-software/#chrome","text":"{% embed url=\"https://www.google.com/chrome/\" %} \u76ee\u524d Chrome \u5e94\u8be5\u662f\u6700\u53d7\u6b22\u8fce\u7684\u6d4f\u89c8\u5668\uff1a \u8fd9\u91cc\u5efa\u8bae\u4f7f\u7528 Chrome \u4f5c\u4e3a\u4e3b\u529b\u6d4f\u89c8\u5668\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u7b80\u6d01 \u63d2\u4ef6\u5f3a\u5927\u4e14\u514d\u8d39\uff08Safari \u7684\u67d0\u4e9b\u63d2\u4ef6\u662f\u6536\u8d39\u7684\uff09","title":"Chrome"},{"location":"macos-software/#_6","text":"","title":"\u5e38\u7528\u63d2\u4ef6"},{"location":"macos-software/#adblock-plus","text":"\u62e6\u622a\u5e7f\u544a\u7684\u597d\u5de5\u5177\u3002","title":"Adblock Plus"},{"location":"macos-software/#tampermonkey","text":"\u811a\u672c\u7ba1\u7406\u5668\uff0c\u4f60\u53ef\u4ee5\u627e\u5230\u652f\u6301\u5404\u79cd\u529f\u80fd\u7684\u811a\u672c\uff0c\u6bd4\u5982\uff1a \u53bb\u5e7f\u544a \u4e0b\u8f7d\u89c6\u9891 \u4f60\u53ef\u4ee5\u81ea\u5df1\u5199 js \u811a\u672c\u4ee5\u5b9e\u73b0\u4e00\u5207\u529f\u80fd","title":"Tampermonkey"},{"location":"macos-software/#proxy-switchyomega","text":"\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u5207\u6362\u4ee3\u7406\u670d\u52a1\u5668\u3002","title":"Proxy SwitchyOmega"},{"location":"macos-software/#octotree","text":"\u53ef\u4ee5\u5728 GitHub \u9875\u9762\u5c55\u793a\u4ee3\u7801\u6587\u4ef6\u7ed3\u6784\uff0c\u975e\u5e38\u65b9\u4fbf\uff0c\u5982\u56fe\uff1a","title":"Octotree"},{"location":"macos-software/#_7","text":"","title":"\u5f00\u53d1\u8f6f\u4ef6"},{"location":"macos-software/#xcode","text":"Xcode \u662f macOS \u4e0a\u7684 IDE\uff0c\u53ef\u4ee5\u5f00\u53d1 macOS\u3001iPhone\u3001iPad\u3001AppleWatch \u7b49\u5e73\u53f0\u4e0a\u7684\u5e94\u7528\uff0c\u5982\u679c\u4f60\u5e0c\u671b\u5728 iPhone \u8fdb\u884c\u8c03\u8bd5\uff0c\u4f60\u8fd8\u9700\u8981\u8d2d\u4e70 99$ \u7684\u5f00\u53d1\u8005\u8bc1\u4e66\u3002\u6211\u4eec\u4e00\u822c\u4ece AppStore \u4e0a\u4e0b\u8f7d Xcode\u3002","title":"Xcode"},{"location":"macos-software/#pycharm","text":"PyCharm \u662f\u6211\u7ecf\u5e38\u4f7f\u7528\u7684 Python IDE\uff0c\u5b83\u652f\u6301\u4ee3\u7801\u9ad8\u4eae\u3001\u4ee3\u7801\u63d0\u793a\u3001\u8c03\u8bd5\u65ad\u70b9\u7b49\u529f\u80fd\uff0c\u4e13\u4e1a\u7248\u8fd8\u652f\u6301\u8fdc\u7a0b\u8c03\u8bd5\uff0c\u975e\u5e38\u9002\u5408\u6df1\u5ea6\u5b66\u4e60\u4ece\u4e1a\u4eba\u5458\u4f7f\u7528\u3002 \u56e0\u4e3a\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u90fd\u4e0d\u662f\u76f4\u63a5\u5728\u8bad\u7ec3\u673a\u5668\u4e0a\u5199\u4ee3\u7801\uff0c\u800c\u662f\u4f7f\u7528\u4e00\u4e2a\u7ec8\u7aef\u673a\u5668\u8fdc\u7a0b ssh \u8fdb\u884c\u4ee3\u7801\u8c03\u8bd5\u3002\u90a3\u4e48\u5982\u679c\u6bcf\u6b21\u90fd\u662f\u4e0a\u4f20\u4ee3\u7801\u3001\u8fd0\u884c Python \u811a\u672c\u3001\u770b\u62a5\u9519\uff0c\u90a3\u4e48\u5c31\u4f1a\u975e\u5e38\u4f4e\u6548\uff0c\u56e0\u4e3a\u6709\u53ef\u80fd\u4f60\u8f7d\u5165\u4e86\u4e94\u5206\u949f\u7684\u6570\u636e\u96c6\u4ee5\u540e\uff0c\u62a5\u9519\u6a21\u578b\u7684\u67d0\u4e2a\u5c42\u5199\u9519\u4e86\uff0c\u7136\u540e\u68c0\u67e5\u534a\u5929\uff0c\u4e0a\u4f20\u4e00\u4e2a\u65b0\u7684\u4ee3\u7801\uff0c\u7136\u540e\u9677\u5165\u4e0a\u9762\u7684\u5faa\u73af\u3002 \u9ad8\u6548\u4e00\u70b9\u7684\u65b9\u6cd5\u5c31\u662f\u4f7f\u7528 jupyter notebook \u8fdb\u884c\u5f00\u53d1\uff0c\u5373\u4f7f\u4ee3\u7801\u62a5\u9519\u4e86\u4e5f\u4e0d\u4f1a\u76f4\u63a5\u9000\u51fa\uff0c\u6211\u4eec\u53ef\u4ee5\u5728 jupyter notebook \u91cc\u7ee7\u7eed\u5199\u4ee3\u7801\uff0c\u76f4\u5230\u5199\u51fa\u6b63\u786e\u7684\u4ee3\u7801\u3002\u90a3\u4e48\u8fd9\u4ecd\u7136\u4e0d\u662f\u9ad8\u6548\u7684\u65b9\u6cd5\uff0c\u56e0\u4e3a\u5982\u679c\u6211\u4eec\u6709\u4e00\u4e2a\u9519\u8bef\u53d1\u751f\u5728\u6a21\u578b\u5185\u90e8\u7684 forward \u90e8\u5206\uff0c\u90a3\u4e48\u6211\u4eec\u5c31\u9700\u8981\u7528 print \u5927\u6cd5\u5728\u51fa\u9519\u4ee3\u7801\u7684\u524d\u540e\u8f93\u51fa\u77e9\u9635\u5c3a\u5bf8\u3001\u6570\u636e\u7c7b\u578b\u7b49\u5173\u952e\u6570\u636e\uff0c\u7136\u540e\u6839\u636e\u62a5\u9519\u6765\u4fee bug\u3002 \u90a3\u4e48\u5f53\u6211\u4eec\u51fa\u73b0\u8fd9\u79cd\u62a5\u9519\u7684\u65f6\u5019\uff0c\u4f7f\u7528 PyCharm \u7684\u8fdc\u7a0b\u8c03\u8bd5\u529f\u80fd\u5c31\u975e\u5e38\u65b9\u4fbf\u4e86\uff0c\u6211\u4eec\u53ef\u4ee5\u5728\u51fa\u9519\u7684\u4ee3\u7801\u524d\u9762\u4e0b\u65ad\u70b9\uff0c\u7136\u540e\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u6bcf\u4e2a\u77e9\u9635\u7684\u5c3a\u5bf8\uff0c\u6a21\u578b\u7684\u6bcf\u4e00\u5c42\u7684\u53c2\u6570\uff0c\u4e0d\u9700\u8981\u5199\u8bb8\u591a print \u53bb\u5b9e\u73b0\u6211\u4eec\u7684\u60f3\u6cd5\u3002\u5982\u679c\u4ee3\u7801\u62a5\u9519\u662f\u4e00\u4e2a\u96640\u9519\u8bef\uff0c\u4f60\u8fd8\u53ef\u4ee5\u76f4\u63a5\u5728\u53d8\u91cf\u76d1\u89c6\u5668\u91cc\u9762\u589e\u52a0\u4e00\u4e2a x.mean() \u7684\u6761\u76ee\uff0c\u7136\u540e\u5b9e\u65f6\u67e5\u770b x \u7684\u5747\u503c\uff0c\u4e0d\u9700\u8981\u91cd\u65b0\u8fd0\u884c\u4ee3\u7801\u3002","title":"PyCharm"},{"location":"macos-software/#github-desktop","text":"GitHub Desktop \u662f GitHub \u5b98\u65b9\u5ba2\u6237\u7aef\uff0c\u65b0\u624b\u5fc5\u5907\u3002","title":"GitHub Desktop"},{"location":"macos-software/#postman","text":"\u4e00\u6b3e\u975e\u5e38\u597d\u7528\u7684 API \u6d4b\u8bd5\u5de5\u5177\uff0c\u5b83\u53ef\u4ee5\u6a21\u62df\u53d1\u9001 GET\u3001POST \u7b49\u8bf7\u6c42\uff0c\u652f\u6301 JSON \u8bed\u6cd5\u9ad8\u4eae\u3002","title":"Postman"},{"location":"macos-software/#_8","text":"Netron Karabiner-Elements The Unarchiver iStat Menus Caffeine DaisyDisk","title":"\u5b9e\u7528\u5de5\u5177"},{"location":"macos-software/#netron","text":"\u5b83\u662f\u4e00\u4e2a\u53ef\u89c6\u5316\u6a21\u578b\u7ed3\u6784\u7684\u8f6f\u4ef6\uff0c\u652f\u6301\u7684\u6a21\u578b\u6587\u4ef6\u683c\u5f0f\u6709\uff1a ONNX ( .onnx , .pb , .pbtxt ), Keras ( .h5 , .keras ), Core ML ( .mlmodel ), Caffe2 ( predict_net.pb , predict_net.pbtxt ), MXNet ( .model , -symbol.json ) and TensorFlow Lite ( .tflite ). Netron has experimental support for Caffe ( .caffemodel , .prototxt ), PyTorch ( .pth ), Torch ( .t7 ), CNTK ( .model , .cntk ), PaddlePaddle ( __model__ ), Darknet ( .cfg ), scikit-learn ( .pkl ), TensorFlow.js ( model.json , .pb ) and TensorFlow ( .pb , .meta , .pbtxt ).","title":"Netron"},{"location":"macos-software/#karabiner-elements","text":"Karabiner-Elements \u662f\u4e00\u4e2a\u6539\u952e\u5de5\u5177\uff0c\u673a\u68b0\u952e\u76d8\u5fc5\u5907\u8f6f\u4ef6\u3002 \u9002\u7528\u4e8emacOS\u7684\u529f\u80fd\u5f3a\u5927\u4e14\u7a33\u5b9a\u7684\u952e\u76d8\u5b9a\u5236\u5668\u3002 \u6211\u628a\u6211\u7684\u673a\u68b0\u952e\u76d8\u7684 Command \u952e\u548c Option \u952e\u66ff\u6362\u4e86\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u50cf\u4f7f\u7528\u539f\u751f\u952e\u76d8\u4e00\u6837\u4f7f\u7528\u6211\u7684\u673a\u68b0\u952e\u76d8\u3002\u4f60\u8fd8\u53ef\u4ee5\u628a\u952e\u76d8\u4e0a\u7684 Windows \u952e\u548c Alt \u952e\u4ea4\u6362\u4f4d\u7f6e\u3002","title":"Karabiner-Elements"},{"location":"macos-software/#the-unarchiver","text":"\u8fd9\u662f\u4e00\u4e2a\u89e3\u538b\u7f29\u8f6f\u4ef6\uff0c\u53ef\u4ee5\u76f4\u63a5\u5728 App Store \u4e0a\u4e0b\u8f7d\uff0c\u514d\u8d39\uff0c\u652f\u6301 zip\u3001rar\u3001tar \u7b49\u683c\u5f0f\u3002 The Unarchiver \u662f\u4e00\u6b3e\u7b80\u5355\u6613\u7528\u7684\u5c0f\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u89e3\u538b\u8bb8\u591a\u4e0d\u540c\u7c7b\u578b\u7684\u5b58\u6863\u6587\u4ef6\u3002 \u5b83\u80fd\u591f\u6253\u5f00 Zip\u3001RAR\uff08\u5305\u62ec v5\uff09\u30017-zip\u3001Tar\u3001Gzip \u548c Bzip2 \u7b49\u5e38\u89c1\u683c\u5f0f\u3002 \u5b83\u8fd8\u80fd\u6253\u5f00\u8bb8\u591a\u65e7\u683c\u5f0f\uff0c\u4f8b\u5982 StuffIt\u3001DiskDoubler\u3001LZH\u3001ARJ \u548c ARC\u3002 \u5b83\u8fd8\u80fd\u6253\u5f00\u5176\u4ed6\u5404\u79cd\u6587\u4ef6\uff0c\u4f8b\u5982 ISO \u548c BIN \u78c1\u76d8\u955c\u50cf\u3001\u90e8\u5206 Windows .EXE \u5b89\u88c5\u7a0b\u5e8f\u3002 \u8be5\u5217\u8868\u5b9e\u9645\u4e0a\u5f88\u957f - \u6709\u5173\u5b8c\u6574\u5217\u8868\uff0c\u8bf7\u67e5\u770b\u7a0b\u5e8f\u4e3b\u9875\u3002","title":"The Unarchiver"},{"location":"macos-software/#caffeine","text":"\u5b83\u53ef\u4ee5\u9632\u6b62\u4f60\u7684\u7535\u8111\u8fdb\u5165\u7761\u7720\uff0c\u4f60\u53ea\u9700\u8981\u5728\u72b6\u6001\u680f\u70b9\u4e00\u4e0b\u5c31\u53ef\u4ee5\u6253\u5f00\u548c\u5173\u95ed\uff0c\u6bd4\u5728\u8bbe\u7f6e\u91cc\u9762\u64cd\u4f5c\u65b9\u4fbf\u4e0d\u5c11\u3002","title":"Caffeine"},{"location":"macos-software/#istat-menus","text":"\u8fd9\u4e2a\u8f6f\u4ef6\u53ef\u4ee5\u76d1\u63a7 Mac \u7684 CPU\u3001\u5185\u5b58\u3001\u7f51\u901f\u7b49\u4fe1\u606f\u3002\u6536\u8d39\u3002 \u901a\u8fc7\u8fd9\u4e2a\u8f6f\u4ef6\uff0c\u6211\u53ef\u4ee5\u76f4\u89c2\u5730\u67e5\u770b\u6211\u8dd1\u7a0b\u5e8f\u7684\u65f6\u5019 CPU \u6709\u6ca1\u6709\u5168\u90e8\u7528\u4e0a\uff0c\u5b83\u5728\u72b6\u6001\u680f\u5e76\u4e0d\u4f1a\u5360\u7528\u592a\u591a\u7a7a\u95f4\uff0c\u4e0b\u8f7d\u4e1c\u897f\u7684\u65f6\u5019\u4e5f\u53ef\u4ee5\u76d1\u63a7\u7f51\u901f\u3002","title":"iStat Menus"},{"location":"macos-software/#daisydisk","text":"\u8fd9\u662f\u4e00\u4e2a\u975e\u5e38\u597d\u7528\u7684\u78c1\u76d8\u7a7a\u95f4\u6574\u7406\u5de5\u5177\uff0c\u4f60\u53ef\u4ee5\u68c0\u67e5\u4f60\u7684 Mac \u4e0a\u5360\u7528\u7a7a\u95f4\u8f83\u5927\u7684\u6587\u4ef6\u90fd\u5728\u54ea\u91cc\u3002\u6536\u8d39\u3002","title":"DaisyDisk"},{"location":"macos-software/#_9","text":"","title":"\u865a\u62df\u673a"},{"location":"macos-software/#parallels-desktop","text":"\u8fd9\u662f\u4e00\u6b3e\u975e\u5e38\u4f18\u79c0\u7684\u865a\u62df\u673a\u8f6f\u4ef6\uff0c\u6536\u8d39\u3002 \u5b83\u521b\u65b0\u7684\u878d\u5408\u6a21\u5f0f\u53ef\u4ee5\u8ba9\u4f60\u5728 Mac \u684c\u9762\u4e0b\uff0c\u5728\u4f7f\u7528 Windows \u8f6f\u4ef6\u7684\u65f6\u5019\u611f\u89c9\u50cf\u5728\u4f7f\u7528 Mac \u539f\u751f\u7684\u8f6f\u4ef6\uff0c\u6bd4\u5982\uff1a \u540e\u9762\u7684\u7a97\u53e3\u662f Finder\uff0c\u524d\u9762\u7684\u7a97\u53e3\u662f\u4e00\u4e2a Windows \u5e94\u7528\uff0c\u4f7f\u7528 Parallels Desktop \u53ef\u4ee5\u8ba9\u4f60\u65e0\u7f1d\u4f7f\u7528 Mac \u548c Windows \u7684\u5e94\u7528\u3002","title":"Parallels Desktop"},{"location":"offline-python-environment/","text":"\u79bb\u7ebf Python \u73af\u5883 \u6709\u65f6\u56e0\u4e3a\u9650\u5236\uff0c\u6211\u4eec\u4e0d\u80fd\u591f\u5728\u76ee\u6807\u673a\u5668\u4e0a\u4f7f\u7528\u7f51\u7edc\u5b89\u88c5 Python \u73af\u5883\uff0c\u90a3\u4e48\u5982\u4f55\u79bb\u7ebf\u6784\u5efa Anaconda \u865a\u62df\u73af\u5883\uff0c\u4ee5\u53ca\u5982\u4f55\u79bb\u7ebf\u5b89\u88c5\u5404\u79cd Python \u5e93\uff0c\u5c31\u662f\u4e00\u4e2a\u5fc5\u987b\u8981\u601d\u8003\u7684\u95ee\u9898\u3002\u6211\u4f1a\u5728\u8fd9\u7bc7\u6587\u7ae0\u91cc\u4ecb\u7ecd\u6211\u5728\u79bb\u7ebf\u5b89\u88c5 Anaconda \u548c\u914d\u7f6e Python \u73af\u5883\u65b9\u9762\u7684\u4e00\u4e9b\u7ecf\u9a8c\u3002 \u79bb\u7ebf\u6784\u5efa Python \u73af\u5883\u7684\u6784\u5efa\u9700\u8981\uff1a \u5728\u6709\u7f51\u7684\u673a\u5668\u4e0a\uff1a \u4e0b\u8f7d\u670d\u52a1\u5668\u5bf9\u5e94\u7684 conda \u5b89\u88c5\u5305 \u4e0b\u8f7d Python \u865a\u62df\u73af\u5883 pkg \u6587\u4ef6 \u4e0b\u8f7d Python \u5e93\u7684 whl \u6587\u4ef6 \u5728\u79bb\u7ebf\u670d\u52a1\u5668\u4e0a\uff1a \u5b89\u88c5 conda \u5b89\u88c5 Python \u865a\u62df\u73af\u5883 \u5b89\u88c5 Python \u5e93 \u63d0\u793a\uff1a \u5982\u679c\u79bb\u7ebf\u670d\u52a1\u5668\u5df2\u7ecf\u5b89\u88c5 conda\uff0c\u53ef\u4ee5\u4e0d\u7528\u91cd\u590d\u5b89\u88c5 \u5982\u679c\u79bb\u7ebf\u670d\u52a1\u5668\u5df2\u7ecf\u6709\u4f60\u9700\u8981\u7684 Python \u7248\u672c\u5bf9\u5e94\u7684\u865a\u62df\u73af\u5883\uff0c\u53ef\u4ee5\u4f7f\u7528 conda create --clone \u514b\u9686\u65e7\u7684\u865a\u62df\u73af\u5883 \u4e0b\u8f7d conda \u5b89\u88c5\u5305 \u5982\u679c\u4f60\u4f7f\u7528\u7684 Python \u7248\u672c\u662f Python 3.7\uff0c\u90a3\u4e48\u76f4\u63a5\u4e0b\u8f7d\u6700\u65b0\u7684 Anaconda \u5373\u53ef\uff0c\u81ea\u5e26 Python 3.7 \u4ee5\u53ca\u8bb8\u591a\u673a\u5668\u5b66\u4e60\u73af\u5883\uff0c\u53ea\u9700\u8981\u79bb\u7ebf\u5b89\u88c5\u4e00\u4e9b\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u8fd9\u90e8\u5206\u5185\u5bb9\u53ef\u4ee5\u53c2\u8003\u4e0b\u9762\u7684\u4e0b\u8f7dwhl\u6587\u4ef6\u3002 \u5982\u679c\u4f60\u4f7f\u7528 Python 3.7 \u4ee5\u4e0b\u7684\u7248\u672c\uff0c\u5982 Python 3.6\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u53ea\u4e0b\u8f7d Miniconda\uff0c\u7136\u540e\u901a\u8fc7 pkg \u91cc\u5148\u5b89\u88c5\u4f60\u60f3\u8981\u7684Python \u7248\u672c\u3002\u4e3a\u4ec0\u4e48\u4e0d\u4e0b\u8f7d Anaconda \u5462\uff1f\u56e0\u4e3a\u5b83\u5f88\u5927\uff0c\u800c\u4e14\u91cc\u9762\u7684 Python \u7248\u672c\u5e76\u4e0d\u662f\u6211\u4eec\u9700\u8981\u7684\u7248\u672c\u3002 \u76ee\u524d\u6700\u65b0\u7684 Anaconda \u548c Miniconda \u4e0b\u8f7d\u94fe\u63a5\uff1a https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \u5982\u679c\u4f60\u9047\u5230\u4e86\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Anaconda \u955c\u50cf \uff1a https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.07-Linux-x86_64.sh https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh \u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4e0b\u8f7d\uff1a mkdir -p ~/Downloads/offline cd ~/Downloads/offline wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh \u4e0b\u8f7d pkg \u6587\u4ef6\u548c whl \u6587\u4ef6 pip download \u53ef\u4ee5\u4e0b\u8f7d\u4f60\u6240\u9700\u8981\u548c\u4f9d\u8d56\u7684 Python \u5e93\u5bf9\u5e94\u7684 whl \u5b89\u88c5\u5305\uff0c\u4f46\u662f\u4f60\u5fc5\u987b\u786e\u4fdd\u7cfb\u7edf\u5185\u6838\u548c Python \u7248\u672c\u4e00\u81f4\u3002\u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f Mac\uff0c\u800c\u76ee\u6807\u673a\u5668\u662f Linux\uff0c\u90a3\u4e48\u4f60\u5c31\u4e0d\u80fd\u591f\u4f7f\u7528 pip download \u547d\u4ee4\u5f88\u65b9\u4fbf\u5730\u4e0b\u8f7d\u6240\u6709\u4f9d\u8d56\u7684 whl \u6587\u4ef6\u3002\u4e3a\u4e86\u7b80\u5316\u8fd9\u4e00\u95ee\u9898\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Docker \u521b\u5efa\u4e00\u4e2a Linux \u73af\u5883\u6765\u5b8c\u6210\u4e0b\u8f7d\u4efb\u52a1\u3002 \u542f\u52a8 miniconda \u5bb9\u5668 \u901a\u8fc7 -v \u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06 Docker \u5185\u90e8\u7684 /data \u8def\u5f84\u548c\u672c\u5730\u7684 ~/Downloads/offline \u8def\u5f84\u94fe\u63a5\u8d77\u6765\uff0c\u8fd9\u6837\u5f53\u6211\u4eec\u4e0b\u8f7d\u5230 /data \u65f6\uff0c\u5c31\u53ef\u4ee5\u5728\u672c\u673a\u7684 ~/Downloads/offline \u6587\u4ef6\u5939\u91cc\u770b\u5230\u3002 docker run -it -v ~/Downloads/offline:/data -w /data continuumio/miniconda \u6dfb\u52a0 conda \u6e90\uff08\u53ef\u9009\uff09 \u901a\u8fc7\u6dfb\u52a0 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Anaconda \u955c\u50cf \uff0c\u6211\u4eec\u53ef\u4ee5\u52a0\u901f\u4e0b\u8f7d\u8fc7\u7a0b\u3002 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --set show_channel_urls yes \u4e0b\u8f7d pkg \u6587\u4ef6 Anaconda \u6240\u6709\u7684\u5e93\u90fd\u662f\u901a\u8fc7 pkg \u5b89\u88c5\u7684\uff0c\u6211\u4eec\u53ea\u8981\u4e0b\u8f7d\u8fd9\u4e9b pkg \u6587\u4ef6\uff0c\u5373\u53ef\u521b\u5efa\u6211\u4eec\u60f3\u8981\u7684\u73af\u5883\u3002 \u9996\u5148\u5220\u9664 miniconda docker \u91cc\u5df2\u6709\u7684 pkg \u6587\u4ef6\uff0c\u56e0\u4e3a miniconda \u9ed8\u8ba4\u5b89\u88c5\u4e86 Python 2.7\uff0c\u6211\u4eec\u4e0d\u5e0c\u671b\u5728\u5b89\u88c5 Python 3.6 \u7684\u65f6\u5019\u6709 Python 2.7 \u7684 pkg \u6587\u4ef6\u3002 \u7136\u540e\u6211\u4eec\u521b\u5efa\u4e00\u4e2a Python 3.6 \u73af\u5883\u3002\u5982\u679c\u4f60\u5e0c\u671b\u5b89\u88c5 Python \u7684\u5176\u4ed6\u7248\u672c\uff0c\u53ef\u4ee5\u5728\u521b\u5efa\u73af\u5883\u7684\u65f6\u5019\u81ea\u884c\u4fee\u6539\u7248\u672c\u53f7\u3002 \u521b\u5efa\u597d\u73af\u5883\u4ee5\u540e\uff0c\u6240\u6709\u9700\u8981\u7684 pkg \u6587\u4ef6\uff08\u540e\u7f00\u540d\u662f .tar.bz2 \uff09\u5c31\u4f1a\u4e0b\u8f7d\u5230 /opt/conda/pkgs \u76ee\u5f55\u4e0b\uff0c\u6211\u4eec\u53ea\u9700\u8981\u628a\u5b83\u4eec\u62f7\u5230 /data \u76ee\u5f55\u4e0b\uff0c\u5373\u53ef\u5728\u672c\u673a\u7684\u4e0b\u8f7d\u6587\u4ef6\u5939\u91cc\u770b\u89c1\u3002 rm -rf /opt/conda/pkgs conda create -n ypw python = 3 .6 source activate ypw mkdir -p /data/pkgs cd /opt/conda/pkgs cp *.tar.bz2 /data/pkgs \u914d\u7f6e pip \u6e90\uff08\u53ef\u9009\uff09 \u901a\u8fc7\u6dfb\u52a0 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Pypi \u955c\u50cf \uff0c\u6211\u4eec\u53ef\u4ee5\u52a0\u901f\u4e0b\u8f7d\u8fc7\u7a0b\u3002 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple \u4e0b\u8f7d whl \u6587\u4ef6 whl \u6587\u4ef6\u5c31\u662f\u6211\u4eec\u5e38\u8bf4\u7684 Python \u5e93\u7684\u5b89\u88c5\u6587\u4ef6\uff0c\u4e0b\u9762\u662f\u6211\u5e38\u7528\u7684 Python \u5e93\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u81ea\u5df1\u7684\u9700\u8981\u8fdb\u884c\u4fee\u6539\u3002 mkdir -p /data/whls cd /data/whls pip download jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx \u5728\u79bb\u7ebf\u673a\u5668\u4e0a\u8fdb\u884c\u79bb\u7ebf\u5b89\u88c5 \u5c06\u79bb\u7ebf\u5305\u4f20\u5230\u79bb\u7ebf\u673a\u5668\u4e0a \u4e0b\u8f7d\u597d\u6240\u6709\u9700\u8981\u7684\u79bb\u7ebf\u5b89\u88c5\u5305\u4ee5\u540e\uff0c\u6211\u4eec\u5c31\u9700\u8981\u5c06\u5b83\u4eec\u4f20\u5230\u79bb\u7ebf\u670d\u52a1\u5668\u4e0a\uff0c\u7136\u540e\u9010\u4e2a\u5b89\u88c5\u3002\u5982\u679c\u4f60\u7684\u673a\u5668\u4e0d\u652f\u6301 rsync \u547d\u4ee4\uff0c\u53ef\u4ee5\u4f7f\u7528 scp \u547d\u4ee4\u3002 rsync -avP ~/Downloads/offline fat:~/ \u5b89\u88c5 conda \u5b89\u88c5 conda \u76f4\u63a5\u4f7f\u7528 bash \u8fd0\u884c\uff0c\u7136\u540e\u6309\u7167\u63d0\u793a\u8fdb\u884c\u5373\u53ef\u3002 bash ~/offline/Miniconda3-latest-Linux-x86_64.sh \u521b\u5efa Python \u865a\u62df\u73af\u5883 \u5148\u521b\u5efa\u4e00\u4e2a\u7a7a\u73af\u5883\uff0c\u7136\u540e\u5b89\u88c5\u5df2\u7ecf\u4e0b\u8f7d\u597d\u7684 pkg \u6587\u4ef6\uff0c\u4f60\u5c31\u53ef\u4ee5\u79bb\u7ebf\u521b\u5efa\u4e00\u4e2a Python 3.6 \u7684\u73af\u5883\u3002 conda create -n ypw --offline source activate ypw conda install --offline ~/offline/pkgs/* \u5b89\u88c5 whl \u5e93 \u6700\u540e\uff0c\u4f7f\u7528 pip \u79bb\u7ebf\u5b89\u88c5\u4e0b\u8f7d\u597d\u7684 whl \u6587\u4ef6\u3002 pip install --no-index --find-links = file:///home/richinfo/offline/whls jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx","title":"\u79bb\u7ebf\u5b89\u88c5 Python \u73af\u5883"},{"location":"offline-python-environment/#python","text":"\u6709\u65f6\u56e0\u4e3a\u9650\u5236\uff0c\u6211\u4eec\u4e0d\u80fd\u591f\u5728\u76ee\u6807\u673a\u5668\u4e0a\u4f7f\u7528\u7f51\u7edc\u5b89\u88c5 Python \u73af\u5883\uff0c\u90a3\u4e48\u5982\u4f55\u79bb\u7ebf\u6784\u5efa Anaconda \u865a\u62df\u73af\u5883\uff0c\u4ee5\u53ca\u5982\u4f55\u79bb\u7ebf\u5b89\u88c5\u5404\u79cd Python \u5e93\uff0c\u5c31\u662f\u4e00\u4e2a\u5fc5\u987b\u8981\u601d\u8003\u7684\u95ee\u9898\u3002\u6211\u4f1a\u5728\u8fd9\u7bc7\u6587\u7ae0\u91cc\u4ecb\u7ecd\u6211\u5728\u79bb\u7ebf\u5b89\u88c5 Anaconda \u548c\u914d\u7f6e Python \u73af\u5883\u65b9\u9762\u7684\u4e00\u4e9b\u7ecf\u9a8c\u3002 \u79bb\u7ebf\u6784\u5efa Python \u73af\u5883\u7684\u6784\u5efa\u9700\u8981\uff1a \u5728\u6709\u7f51\u7684\u673a\u5668\u4e0a\uff1a \u4e0b\u8f7d\u670d\u52a1\u5668\u5bf9\u5e94\u7684 conda \u5b89\u88c5\u5305 \u4e0b\u8f7d Python \u865a\u62df\u73af\u5883 pkg \u6587\u4ef6 \u4e0b\u8f7d Python \u5e93\u7684 whl \u6587\u4ef6 \u5728\u79bb\u7ebf\u670d\u52a1\u5668\u4e0a\uff1a \u5b89\u88c5 conda \u5b89\u88c5 Python \u865a\u62df\u73af\u5883 \u5b89\u88c5 Python \u5e93 \u63d0\u793a\uff1a \u5982\u679c\u79bb\u7ebf\u670d\u52a1\u5668\u5df2\u7ecf\u5b89\u88c5 conda\uff0c\u53ef\u4ee5\u4e0d\u7528\u91cd\u590d\u5b89\u88c5 \u5982\u679c\u79bb\u7ebf\u670d\u52a1\u5668\u5df2\u7ecf\u6709\u4f60\u9700\u8981\u7684 Python \u7248\u672c\u5bf9\u5e94\u7684\u865a\u62df\u73af\u5883\uff0c\u53ef\u4ee5\u4f7f\u7528 conda create --clone \u514b\u9686\u65e7\u7684\u865a\u62df\u73af\u5883","title":"\u79bb\u7ebf Python \u73af\u5883"},{"location":"offline-python-environment/#conda","text":"\u5982\u679c\u4f60\u4f7f\u7528\u7684 Python \u7248\u672c\u662f Python 3.7\uff0c\u90a3\u4e48\u76f4\u63a5\u4e0b\u8f7d\u6700\u65b0\u7684 Anaconda \u5373\u53ef\uff0c\u81ea\u5e26 Python 3.7 \u4ee5\u53ca\u8bb8\u591a\u673a\u5668\u5b66\u4e60\u73af\u5883\uff0c\u53ea\u9700\u8981\u79bb\u7ebf\u5b89\u88c5\u4e00\u4e9b\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u8fd9\u90e8\u5206\u5185\u5bb9\u53ef\u4ee5\u53c2\u8003\u4e0b\u9762\u7684\u4e0b\u8f7dwhl\u6587\u4ef6\u3002 \u5982\u679c\u4f60\u4f7f\u7528 Python 3.7 \u4ee5\u4e0b\u7684\u7248\u672c\uff0c\u5982 Python 3.6\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u53ea\u4e0b\u8f7d Miniconda\uff0c\u7136\u540e\u901a\u8fc7 pkg \u91cc\u5148\u5b89\u88c5\u4f60\u60f3\u8981\u7684Python \u7248\u672c\u3002\u4e3a\u4ec0\u4e48\u4e0d\u4e0b\u8f7d Anaconda \u5462\uff1f\u56e0\u4e3a\u5b83\u5f88\u5927\uff0c\u800c\u4e14\u91cc\u9762\u7684 Python \u7248\u672c\u5e76\u4e0d\u662f\u6211\u4eec\u9700\u8981\u7684\u7248\u672c\u3002 \u76ee\u524d\u6700\u65b0\u7684 Anaconda \u548c Miniconda \u4e0b\u8f7d\u94fe\u63a5\uff1a https://repo.anaconda.com/archive/Anaconda3-2019.07-Linux-x86_64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \u5982\u679c\u4f60\u9047\u5230\u4e86\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Anaconda \u955c\u50cf \uff1a https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.07-Linux-x86_64.sh https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh \u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4e0b\u8f7d\uff1a mkdir -p ~/Downloads/offline cd ~/Downloads/offline wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh","title":"\u4e0b\u8f7d conda \u5b89\u88c5\u5305"},{"location":"offline-python-environment/#pkg-whl","text":"pip download \u53ef\u4ee5\u4e0b\u8f7d\u4f60\u6240\u9700\u8981\u548c\u4f9d\u8d56\u7684 Python \u5e93\u5bf9\u5e94\u7684 whl \u5b89\u88c5\u5305\uff0c\u4f46\u662f\u4f60\u5fc5\u987b\u786e\u4fdd\u7cfb\u7edf\u5185\u6838\u548c Python \u7248\u672c\u4e00\u81f4\u3002\u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f Mac\uff0c\u800c\u76ee\u6807\u673a\u5668\u662f Linux\uff0c\u90a3\u4e48\u4f60\u5c31\u4e0d\u80fd\u591f\u4f7f\u7528 pip download \u547d\u4ee4\u5f88\u65b9\u4fbf\u5730\u4e0b\u8f7d\u6240\u6709\u4f9d\u8d56\u7684 whl \u6587\u4ef6\u3002\u4e3a\u4e86\u7b80\u5316\u8fd9\u4e00\u95ee\u9898\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Docker \u521b\u5efa\u4e00\u4e2a Linux \u73af\u5883\u6765\u5b8c\u6210\u4e0b\u8f7d\u4efb\u52a1\u3002","title":"\u4e0b\u8f7d pkg \u6587\u4ef6\u548c whl \u6587\u4ef6"},{"location":"offline-python-environment/#miniconda","text":"\u901a\u8fc7 -v \u53c2\u6570\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06 Docker \u5185\u90e8\u7684 /data \u8def\u5f84\u548c\u672c\u5730\u7684 ~/Downloads/offline \u8def\u5f84\u94fe\u63a5\u8d77\u6765\uff0c\u8fd9\u6837\u5f53\u6211\u4eec\u4e0b\u8f7d\u5230 /data \u65f6\uff0c\u5c31\u53ef\u4ee5\u5728\u672c\u673a\u7684 ~/Downloads/offline \u6587\u4ef6\u5939\u91cc\u770b\u5230\u3002 docker run -it -v ~/Downloads/offline:/data -w /data continuumio/miniconda","title":"\u542f\u52a8 miniconda \u5bb9\u5668"},{"location":"offline-python-environment/#conda_1","text":"\u901a\u8fc7\u6dfb\u52a0 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Anaconda \u955c\u50cf \uff0c\u6211\u4eec\u53ef\u4ee5\u52a0\u901f\u4e0b\u8f7d\u8fc7\u7a0b\u3002 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --set show_channel_urls yes","title":"\u6dfb\u52a0 conda \u6e90\uff08\u53ef\u9009\uff09"},{"location":"offline-python-environment/#pkg","text":"Anaconda \u6240\u6709\u7684\u5e93\u90fd\u662f\u901a\u8fc7 pkg \u5b89\u88c5\u7684\uff0c\u6211\u4eec\u53ea\u8981\u4e0b\u8f7d\u8fd9\u4e9b pkg \u6587\u4ef6\uff0c\u5373\u53ef\u521b\u5efa\u6211\u4eec\u60f3\u8981\u7684\u73af\u5883\u3002 \u9996\u5148\u5220\u9664 miniconda docker \u91cc\u5df2\u6709\u7684 pkg \u6587\u4ef6\uff0c\u56e0\u4e3a miniconda \u9ed8\u8ba4\u5b89\u88c5\u4e86 Python 2.7\uff0c\u6211\u4eec\u4e0d\u5e0c\u671b\u5728\u5b89\u88c5 Python 3.6 \u7684\u65f6\u5019\u6709 Python 2.7 \u7684 pkg \u6587\u4ef6\u3002 \u7136\u540e\u6211\u4eec\u521b\u5efa\u4e00\u4e2a Python 3.6 \u73af\u5883\u3002\u5982\u679c\u4f60\u5e0c\u671b\u5b89\u88c5 Python \u7684\u5176\u4ed6\u7248\u672c\uff0c\u53ef\u4ee5\u5728\u521b\u5efa\u73af\u5883\u7684\u65f6\u5019\u81ea\u884c\u4fee\u6539\u7248\u672c\u53f7\u3002 \u521b\u5efa\u597d\u73af\u5883\u4ee5\u540e\uff0c\u6240\u6709\u9700\u8981\u7684 pkg \u6587\u4ef6\uff08\u540e\u7f00\u540d\u662f .tar.bz2 \uff09\u5c31\u4f1a\u4e0b\u8f7d\u5230 /opt/conda/pkgs \u76ee\u5f55\u4e0b\uff0c\u6211\u4eec\u53ea\u9700\u8981\u628a\u5b83\u4eec\u62f7\u5230 /data \u76ee\u5f55\u4e0b\uff0c\u5373\u53ef\u5728\u672c\u673a\u7684\u4e0b\u8f7d\u6587\u4ef6\u5939\u91cc\u770b\u89c1\u3002 rm -rf /opt/conda/pkgs conda create -n ypw python = 3 .6 source activate ypw mkdir -p /data/pkgs cd /opt/conda/pkgs cp *.tar.bz2 /data/pkgs","title":"\u4e0b\u8f7d pkg \u6587\u4ef6"},{"location":"offline-python-environment/#pip","text":"\u901a\u8fc7\u6dfb\u52a0 \u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u7684 Pypi \u955c\u50cf \uff0c\u6211\u4eec\u53ef\u4ee5\u52a0\u901f\u4e0b\u8f7d\u8fc7\u7a0b\u3002 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple","title":"\u914d\u7f6e pip \u6e90\uff08\u53ef\u9009\uff09"},{"location":"offline-python-environment/#whl","text":"whl \u6587\u4ef6\u5c31\u662f\u6211\u4eec\u5e38\u8bf4\u7684 Python \u5e93\u7684\u5b89\u88c5\u6587\u4ef6\uff0c\u4e0b\u9762\u662f\u6211\u5e38\u7528\u7684 Python \u5e93\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u81ea\u5df1\u7684\u9700\u8981\u8fdb\u884c\u4fee\u6539\u3002 mkdir -p /data/whls cd /data/whls pip download jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx","title":"\u4e0b\u8f7d whl \u6587\u4ef6"},{"location":"offline-python-environment/#_1","text":"","title":"\u5728\u79bb\u7ebf\u673a\u5668\u4e0a\u8fdb\u884c\u79bb\u7ebf\u5b89\u88c5"},{"location":"offline-python-environment/#_2","text":"\u4e0b\u8f7d\u597d\u6240\u6709\u9700\u8981\u7684\u79bb\u7ebf\u5b89\u88c5\u5305\u4ee5\u540e\uff0c\u6211\u4eec\u5c31\u9700\u8981\u5c06\u5b83\u4eec\u4f20\u5230\u79bb\u7ebf\u670d\u52a1\u5668\u4e0a\uff0c\u7136\u540e\u9010\u4e2a\u5b89\u88c5\u3002\u5982\u679c\u4f60\u7684\u673a\u5668\u4e0d\u652f\u6301 rsync \u547d\u4ee4\uff0c\u53ef\u4ee5\u4f7f\u7528 scp \u547d\u4ee4\u3002 rsync -avP ~/Downloads/offline fat:~/","title":"\u5c06\u79bb\u7ebf\u5305\u4f20\u5230\u79bb\u7ebf\u673a\u5668\u4e0a"},{"location":"offline-python-environment/#conda_2","text":"\u5b89\u88c5 conda \u76f4\u63a5\u4f7f\u7528 bash \u8fd0\u884c\uff0c\u7136\u540e\u6309\u7167\u63d0\u793a\u8fdb\u884c\u5373\u53ef\u3002 bash ~/offline/Miniconda3-latest-Linux-x86_64.sh","title":"\u5b89\u88c5 conda"},{"location":"offline-python-environment/#python_1","text":"\u5148\u521b\u5efa\u4e00\u4e2a\u7a7a\u73af\u5883\uff0c\u7136\u540e\u5b89\u88c5\u5df2\u7ecf\u4e0b\u8f7d\u597d\u7684 pkg \u6587\u4ef6\uff0c\u4f60\u5c31\u53ef\u4ee5\u79bb\u7ebf\u521b\u5efa\u4e00\u4e2a Python 3.6 \u7684\u73af\u5883\u3002 conda create -n ypw --offline source activate ypw conda install --offline ~/offline/pkgs/*","title":"\u521b\u5efa Python \u865a\u62df\u73af\u5883"},{"location":"offline-python-environment/#whl_1","text":"\u6700\u540e\uff0c\u4f7f\u7528 pip \u79bb\u7ebf\u5b89\u88c5\u4e0b\u8f7d\u597d\u7684 whl \u6587\u4ef6\u3002 pip install --no-index --find-links = file:///home/richinfo/offline/whls jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx","title":"\u5b89\u88c5 whl \u5e93"},{"location":"python-environment/","text":"Python \u73af\u5883 \u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6765\u8bf4\uff0cPython \u662f\u5fc5\u4e0d\u53ef\u5c11\u7684\u5de5\u5177\uff0c\u56e0\u4e3a\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u90fd\u652f\u6301 Python\uff08\u6bd4\u5982 TensorFlow\u3001PyTorch\u3001MXNet \u7b49\uff09\u3002\u5728\u6a21\u578b\u5f00\u53d1\u9636\u6bb5\uff0c\u4f7f\u7528 Python \u975e\u5e38\u65b9\u4fbf\uff0c\u5982\u679c\u914d\u5408 Jupyter Notebook \u4f7f\u7528\uff0c\u8fd8\u53ef\u4ee5\u8fdb\u4e00\u6b65\u63d0\u5347\u5f00\u53d1\u6548\u7387\u3002 Miniconda bash \u5b89\u88c5 \u4e0b\u8f7d \u6700\u65b0\u7684 miniconda \u5b89\u88c5\u5305\u3002 20230424 \u4e0b\u8f7d\u7684\u662f Miniconda3-latest-MacOSX-arm64.sh \u547d\u4ee4\u884c\u5b89\u88c5 # bash \u5b89\u88c5\u5305\u8def\u5f84 bash /Users/lhy/Downloads/Miniconda3-latest-MacOSX-arm64.sh \u5b89\u88c5 Miniconda \u540e\uff0c\u4f1a\u81ea\u52a8\u5c06 Miniconda \u7684\u8def\u5f84\u6dfb\u52a0\u5230\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u4f46\u662f\u9700\u8981\u5173\u95ed\u5e76\u91cd\u65b0\u6253\u5f00 shell \u624d\u80fd\u751f\u6548\u3002 \u5982\u679c\u9700\u8981\u5728\u5f53\u524d\u7ec8\u7aef\u4f1a\u8bdd\u4e2d\u7acb\u5373\u751f\u6548\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\uff1a source ~/.zshrc Miniconda brew \u5b89\u88c5 \u547d\u4ee4\u884c\u5b89\u88c5 brew install --cask miniconda \u6b64\u65f6\uff0cconda \u4f1a\u5b89\u88c5\u5728\u8fd9\u4e2a\u8def\u5f84\u4e0b /opt/homebrew/bin/conda \u3002 \u68c0\u67e5 miniconda \u662f\u5426\u5b89\u88c5\u6210\u529f conda --version \u5378\u8f7d miniconda rm -rf conda Anaconda Anaconda \u662f\u4e00\u4e2a Pyhton \u7684\u5305\u7ba1\u7406\u5668\uff0c\u5b83\u53ef\u4ee5\u7b80\u5316 Python \u73af\u5883\u7684\u5b89\u88c5\u3002\u7531\u4e8e Ubuntu \u7cfb\u7edf\u3001macOS \u7cfb\u7edf\u7684\u5c40\u9650\u6027\uff0c\u6211\u4eec\u5c3d\u91cf\u4e0d\u8981\u5728\u7cfb\u7edf\u81ea\u5e26\u7684\u73af\u5883\u91cc\u5b89\u88c5\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u4e0d\u7136\u53ef\u80fd\u4f1a\u51fa\u73b0\u4e00\u4e9b\u4e0d\u53ef\u9884\u6599\u7684\u95ee\u9898\u3002 Anaconda \u4e2d\u7684 numpy\u3001scikit-learn \u7b49\u5e93\u4f7f\u7528\u4e86 Intel MKL \u8fdb\u884c\u52a0\u901f\uff0c\u7406\u8bba\u4e0a\u4f1a\u6bd4 pip \u76f4\u63a5\u5b89\u88c5\u7684\u7248\u672c\u901f\u5ea6\u5feb\u3002 Anaconda \u4e0d\u9700\u8981 root \u6743\u9650\uff0c\u6240\u4ee5\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u5b89\u88c5\u5728\u7528\u6237\u76ee\u5f55\u4e0b\uff0c\u53ea\u8981\u914d\u7f6e\u597d\u73af\u5883\u53d8\u91cf\u5373\u53ef\u4f7f\u7528\uff0c\u5f53\u4f60\u4e0d\u9700\u8981\u5b83\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u76f4\u63a5\u5220\u9664\u5b83\u7684\u76ee\u5f55\uff0c\u7136\u540e\u5c06\u5bf9\u5e94\u7684\u73af\u5883\u53d8\u91cf\u4e00\u8d77\u5220\u9664\u5373\u53ef\u3002 \u4f60\u53ef\u4ee5\u76f4\u63a5 rsync \u6574\u4e2a anaconda \u6587\u4ef6\u5939\u5230\u5176\u4ed6\u76f8\u540c\u786c\u4ef6\u548c\u7cfb\u7edf\u73af\u5883\u7684\u673a\u5668\u4e0a\uff0c\u5b83\u4eec\u7684 Python \u73af\u5883\u53ef\u4ee5\u4fdd\u6301\u7edd\u5bf9\u7684\u7edf\u4e00\uff0c\u5728\u505a\u5206\u5e03\u5f0f\u5e76\u884c\u8bad\u7ec3\u7684\u65f6\u5019\u975e\u5e38\u6709\u7528\u3002 \u5b89\u88c5 Anaconda Anaconda \u5b98\u65b9\u4e0b\u8f7d\u9875\u9762\uff1a https://www.anaconda.com/downloads \u4f60\u53ea\u9700\u8981\u4e0b\u8f7d\u5bf9\u5e94\u7cfb\u7edf\u7684\u5b89\u88c5\u5305\uff0c\u7136\u540e\u76f4\u63a5\u8fd0\u884c\u5b89\u88c5\u5305\u5373\u53ef\u3002 \u547d\u4ee4\u884c\u5b89\u88c5 \u5728 macOS \u4e0a\u5b89\u88c5 Anaconda \u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a wget https://repo.anaconda.com/archive/Anaconda3-2020.02-MacOSX-x86_64.sh bash Anaconda3-2020.02-MacOSX-x86_64.sh \u9700\u8981\u4f7f\u7528 brew \u5b89\u88c5 wget \u547d\u4ee4 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf \uff0c\u5982 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.02-MacOSX-x86_64.sh brew cask \u5b89\u88c5 macOS \u4e0a\u8fd8\u53ef\u4ee5 \u4f7f\u7528 brew cask \u5b89\u88c5 \uff1a brew cask install Anaconda \u914d\u7f6e\u73af\u5883\u53d8\u91cf \u5b89\u88c5\u597d\u4ee5\u540e\uff0c\u6709\u53ef\u80fd\u9700\u8981\u624b\u52a8 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f zsh\uff0c\u4f60\u9700\u8981\u4e3a zsh \u521d\u59cb\u5316\uff1a /usr/local/anaconda3/bin/conda init zsh \u6267\u884c\u4ee5\u540e\uff0c\u5728 ~/.zshrc \u4e2d\u53ef\u4ee5\u770b\u5230\u4e0b\u9762\u7684\u5185\u5bb9\uff1a # >>> conda initialize >>> # !! Contents within this block are managed by 'conda init' !! __conda_setup = \" $( '/home/ypw/anaconda3/bin/conda' 'shell.zsh' 'hook' 2 > /dev/null ) \" if [ $? -eq 0 ] ; then eval \" $__conda_setup \" else if [ -f \"/home/ypw/anaconda3/etc/profile.d/conda.sh\" ] ; then . \"/home/ypw/anaconda3/etc/profile.d/conda.sh\" else export PATH = \"/home/ypw/anaconda3/bin: $PATH \" fi fi unset __conda_setup # <<< conda initialize <<< \u4f7f\u7528 Anaconda \u521b\u5efa\u5176\u4ed6 Python \u73af\u5883 \u5982\u679c\u6211\u4eec\u9700\u8981\u5176\u4ed6 Python \u73af\u5883\uff0c\u53ef\u4ee5\u4f7f\u7528 conda \u521b\u5efa\uff1a conda create -n python2 python = 2 .7 source activate python2 \u53c2\u8003\u94fe\u63a5\uff1a https://conda.io/docs/user-guide/tasks/manage-environments.html \u628a Conda \u7684 Python \u73af\u5883\u6dfb\u52a0\u5230 jupyter \u91cc \u5f53\u4f60\u5e0c\u671b\u5728 jupyter \u91cc\u4f7f\u7528\u4f60\u7684\u865a\u62df\u73af\u5883\u7684\u65f6\u5019\uff0c\u4f60\u9700\u8981\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a conda activate python2 conda install ipykernel python - m ipykernel install -- user -- name python2 -- display - name \"Python 2\" \u5176\u4e2d\u7684 python2 \u662f\u4f60\u7684\u865a\u62df\u73af\u5883\u7684\u540d\u5b57\uff0cdisplay-name \u53ef\u4ee5\u53d6\u4e00\u4e2a\u597d\u542c\u7684\u540d\u5b57\uff0c\u5b83\u4f1a\u5728 jupyter notebook \u5207\u6362 kernel \u7684\u5730\u65b9\u663e\u793a\u3002 \u53c2\u8003\u94fe\u63a5\uff1a https://ipython.readthedocs.io/en/stable/install/kernel_install.html \u5207\u6362 anaconda \u6e90 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf \uff1a nano ~/.condarc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r custom_channels: conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud \u5207\u6362 pip \u6e90 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528\u963f\u91cc\u4e91\u7684\u955c\u50cf\uff1a pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ \u5e38\u7528 pypi \u955c\u50cf\uff1a https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ https://mirrors.163.com/pypi/simple/ https://pypi.doubanio.com/simple/ https://mirrors.ustc.edu.cn/pypi/web/simple/ Python \u5e93 \u4e0b\u9762\u662f\u6211\u8ba4\u4e3a\u6bd4\u8f83\u91cd\u8981\u7684 Python \u5e93\uff1a jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow keras tensorboard tensorboardx \u5b89\u88c5\u5927\u793c\u5305\uff1a pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow keras tensorboardx xlrd openpyxl jupyter \u5728\u5b9e\u9a8c\u9636\u6bb5\uff0c\u5f3a\u70c8\u5efa\u8bae\u4f60\u4f7f\u7528 jupyter notebook \u7f16\u5199\u5b9e\u9a8c\u4ee3\u7801\uff0c\u56e0\u4e3a\u5b83\u4e0e\u5199 Python \u811a\u672c\u7684\u903b\u8f91\u5b8c\u5168\u4e0d\u540c\u3002 \u5b98\u65b9\u4ecb\u7ecd\uff1a Jupyter Notebook\u662f\u4e00\u4e2a\u5f00\u6e90Web\u5e94\u7528\u7a0b\u5e8f\uff0c\u5141\u8bb8\u60a8\u521b\u5efa\u548c\u5171\u4eab\u5305\u542b\u5b9e\u65f6\u4ee3\u7801\uff0c\u516c\u5f0f\uff0c\u53ef\u89c6\u5316\u548c\u53d9\u8ff0\u6587\u672c\u7684\u6587\u6863\u3002\u7528\u9014\u5305\u62ec\uff1a\u6570\u636e\u6e05\u7406\u548c\u8f6c\u6362\uff0c\u6570\u503c\u6a21\u62df\uff0c\u7edf\u8ba1\u5efa\u6a21\uff0c\u6570\u636e\u53ef\u89c6\u5316\uff0c\u673a\u5668\u5b66\u4e60\u7b49\u3002 \u7279\u70b9\uff1a web\u9875\u9762\u4ea4\u4e92\uff0c\u5728\u5404\u4e2a\u5e73\u53f0\u751a\u81f3\u662f\u624b\u673a\u4e0a\u90fd\u6709\u540c\u6837\u7684\u754c\u9762 \u8fd0\u884c\u8fc7\u7684\u4ee3\u7801\u4ea7\u751f\u7684\u53d8\u91cf\u3001\u51fd\u6570\u3001\u7c7b\u4e0d\u4f1a\u6d88\u5931\uff0c\u9664\u975e\u4f60\u91cd\u542f\u5185\u6838 \u4e0d\u4ec5\u652f\u6301\u5199\u4ee3\u7801\uff0c\u663e\u793a\u51fd\u6570\u8f93\u51fa\u7684\u6587\u5b57\uff0c\u8fd8\u652f\u6301\u663e\u793a\u56fe\u7247\uff0c\u751a\u81f3\u5b9e\u73b0\u7b80\u5355\u7684\u4ea4\u4e92\u529f\u80fd \u652f\u6301 Markdown \u7f16\u5199\u6ce8\u91ca\uff0c\u8fd8\u652f\u6301 latex \u516c\u5f0f jupyter_contrib_nbextensions Jupyter Notebook \u63d2\u4ef6\u3002 \u8be5 jupyter_contrib_nbextensions \u8f6f\u4ef6\u5305\u5305\u542b\u4e00\u7cfb\u5217\u793e\u533a\u8d21\u732e\u7684\u975e\u5b98\u65b9\u6269\u5c55\uff0c\u53ef\u4e3aJupyter\u7b14\u8bb0\u672c\u6dfb\u52a0\u529f\u80fd\u3002\u8fd9\u4e9b\u6269\u5c55\u5927\u591a\u662f\u7528Javascript\u7f16\u5199\u7684\uff0c\u5c06\u5728\u60a8\u7684\u6d4f\u89c8\u5668\u4e2d\u672c\u5730\u52a0\u8f7d\u3002 \u6211\u4f7f\u7528\u4e86 \u4ee3\u7801\u6267\u884c\u65f6\u95f4\u63d2\u4ef6 \u548c \u51fd\u6570\u6298\u53e0\u63d2\u4ef6 \u3002 numpy \u79d1\u5b66\u8ba1\u7b97\u5fc5\u5907\u5e93\u3002 NumPy\u662fPython\u8bed\u8a00\u7684\u4e00\u4e2a\u6269\u5c55\u7a0b\u5e8f\u5e93\u3002\u652f\u6301\u9ad8\u7aef\u5927\u91cf\u7684\u7ef4\u5ea6\u6570\u7ec4\u4e0e\u77e9\u9635\u8fd0\u7b97\uff0c\u6b64\u5916\u4e5f\u9488\u5bf9\u6570\u7ec4\u8fd0\u7b97\u63d0\u4f9b\u5927\u91cf\u7684\u6570\u5b66\u51fd\u6570\u5e93\u3002 pandas \u64cd\u4f5c csv \u975e\u5e38\u65b9\u4fbf\uff0cpython \u91cc\u7684 excel\u3002 _pandas_\u662f\u4e00\u4e2a\u5f00\u6e90\u7684\uff0cBSD\u8bb8\u53ef\u7684\u5e93\uff0c\u4e3aPython\u7f16\u7a0b\u8bed\u8a00\u63d0\u4f9b\u9ad8\u6027\u80fd\uff0c\u6613\u4e8e\u4f7f\u7528\u7684\u6570\u636e\u7ed3\u6784\u548c\u6570\u636e\u5206\u6790\u5de5\u5177\u3002 scikit-learn \u673a\u5668\u5b66\u4e60\u6a21\u578b\u5927\u5168\u3002 Python\u4e2d\u7684\u673a\u5668\u5b66\u4e60 \u7b80\u5355\u6709\u6548\u7684\u6570\u636e\u6316\u6398\u548c\u6570\u636e\u5206\u6790\u5de5\u5177 \u53ef\u4f9b\u6240\u6709\u4eba\u8bbf\u95ee\uff0c\u5e76\u53ef\u5728\u5404\u79cd\u73af\u5883\u4e2d\u91cd\u590d\u4f7f\u7528 \u57fa\u4e8eNumPy\uff0cSciPy\u548cmatplotlib\u6784\u5efa \u5f00\u6e90\uff0c\u5546\u4e1a\u4e0a\u53ef\u7528 - BSD\u8bb8\u53ef\u8bc1 \u6ce8\u610f\u5b89\u88c5\u7684\u65f6\u5019\u4e0d\u662f sklearn\uff0c\u800c\u662f scikit-learn\uff1a pip install scikit - learn matplotlib \u753b\u56fe\u5de5\u5177\u3002 Matplotlib\u662f\u4e00\u4e2aPython 2D\u7ed8\u56fe\u5e93\uff0c\u53ef\u4ee5\u751f\u6210\u5404\u79cd\u786c\u62f7\u8d1d\u683c\u5f0f\u548c\u8de8\u5e73\u53f0\u7684\u4ea4\u4e92\u5f0f\u73af\u5883\u7684\u51fa\u7248\u7269\u8d28\u91cf\u6570\u636e\u3002Matplotlib\u53ef\u7528\u4e8ePython\u811a\u672c\u3001IPython shell\u3001Jupyter Notebook \u548c Web\u5e94\u7528\u7a0b\u5e8f\u670d\u52a1\u5668\u548c\u56db\u4e2a\u56fe\u5f62\u7528\u6237\u754c\u9762\u5de5\u5177\u5305\u3002 opencv-python OpenCV \u7684 Python \u5e93\uff0c\u56fe\u50cf\u5904\u7406\u5fc5\u5907\u3002\u6ce8\u610f\u8fd9\u4e0d\u662f\u5b98\u65b9\u7684\u5e93\uff0c\u800c\u662f\u7b2c\u4e09\u65b9\u7f16\u8bd1\u7684\u5e93\u3002 OpenCV\u7684\u5168\u79f0\u662fOpen Source Computer Vision Library\uff0c\u662f\u4e00\u4e2a\u8de8\u5e73\u53f0\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u5e93\u3002 \u5b98\u65b9\u5efa\u8bae\u662f\u4ece\u6e90\u7801\u7f16\u8bd1\uff1a https://docs.opencv.org/3.4.6/d2/de6/tutorial_py_setup_in_ubuntu.html \u5982\u679c\u4f60\u4f7f\u7528\u7684\u529f\u80fd\u4e0d\u662f\u5f88\u590d\u6742\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 pip \u5b89\u88c5 opencv-python \u3002\u5982\u679c\u4f60\u4f7f\u7528\u4e86 opencv-contrib \u91cc\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u5b89\u88c5 opencv-contrib-python \u3002 pillow PIL\uff0c\u53e6\u4e00\u4e2a\u56fe\u50cf\u5904\u7406\u5e93\uff0cPyTorch \u91cc\u7684 torchvision \u6709\u5f88\u591a\u5199\u597d\u7684\u6570\u636e\u589e\u5f3a\u7c7b\uff0c\u5b83\u4eec\u7684\u8f93\u5165\u7c7b\u578b\u662f PIL.Image\u3002 \u8be5\u5e93\u63d0\u4f9b\u5e7f\u6cdb\u7684\u6587\u4ef6\u683c\u5f0f\u652f\u6301\uff0c\u9ad8\u6548\u7684\u5185\u90e8\u8868\u793a\u548c\u76f8\u5f53\u5f3a\u5927\u7684\u56fe\u50cf\u5904\u7406\u529f\u80fd\u3002 \u6838\u5fc3\u56fe\u50cf\u5e93\u65e8\u5728\u5feb\u901f\u8bbf\u95ee\u4ee5\u51e0\u79cd\u57fa\u672c\u50cf\u7d20\u683c\u5f0f\u5b58\u50a8\u7684\u6570\u636e\u3002\u5b83\u5e94\u8be5\u4e3a\u4e00\u822c\u7684\u56fe\u50cf\u5904\u7406\u5de5\u5177\u63d0\u4f9b\u575a\u5b9e\u7684\u57fa\u7840\u3002 tqdm \u8fdb\u5ea6\u6761\u5e93\uff0c\u8017\u65f6\u957f\u7684\u4efb\u52a1\u53ef\u4ee5\u4f7f\u7528 tqdm \u76f4\u89c2\u5730\u5c55\u793a\u4efb\u52a1\u7684\u8fdb\u5ea6\uff0c\u907f\u514d\u7126\u8651\u3002 tqdm \u5728\u963f\u62c9\u4f2f\u8bed\u4e2d\u662f\u201c\u8fdb\u6b65\u201d\uff08 taqadum \uff0c\u062a\u0642\u062f\u0645\uff09\u7684\u610f\u601d\uff0c\u5728\u897f\u73ed\u7259\u8bed\u4e2d\u662f\u201c\u6211\u592a\u7231\u4f60\u4e86\u201d\uff08 te quiero demasiado \uff09\u7684\u7f29\u5199\u3002 \u53ea\u9700\u5728\u4efb\u4f55\u8fed\u4ee3\u5668\u5916\u5305\u4e00\u4e2a tqdm\uff1a tqdm(iterable) \uff0c\u5c31\u80fd\u7acb\u523b\u8ba9\u4f60\u7684\u5faa\u73af\u663e\u793a\u4e00\u4e2a\u806a\u660e\u7684\u8fdb\u5ea6\u6761\uff01 torch \u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u63a8\u8350\u4f7f\u7528\u3002 \u4e00\u4e2a\u5f00\u6e90\u6df1\u5ea6\u5b66\u4e60\u5e73\u53f0\uff0c\u63d0\u4f9b\u4ece\u7814\u7a76\u539f\u578b\u5230\u751f\u4ea7\u90e8\u7f72\u7684\u65e0\u7f1d\u8def\u5f84\u3002 torchvision \u548c PyTorch \u914d\u5957\u4f7f\u7528\u3002 torchvision \u5305\u542b\u4e86\u6d41\u884c\u7684\u6570\u636e\u96c6\uff0c\u9884\u8bad\u7ec3\u6a21\u578b\u548c\u8ba1\u7b97\u673a\u89c6\u89c9\u7684\u5e38\u89c1\u7684\u56fe\u50cf\u53d8\u6362\u3002 tensorflow \u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u5927\u800c\u5168\u3002\u914d\u5907\u663e\u5361\u7684\u673a\u5668\u8bf7\u6309\u7167 Ubuntu \u73af\u5883 \u8fdb\u884c\u914d\u7f6e\u3002 TensorFlow\u662f\u4e00\u4e2a\u7528\u4e8e\u673a\u5668\u5b66\u4e60\u7684\u7aef\u5230\u7aef\u5f00\u6e90\u5e73\u53f0\u3002 \u5b83\u62e5\u6709\u5168\u9762\u3001\u7075\u6d3b\u7684\u5de5\u5177\u3001\u5e93\u548c\u793e\u533a\u8d44\u6e90\u751f\u6001\u7cfb\u7edf\uff0c\u53ef\u8ba9\u7814\u7a76\u4eba\u5458\u63a8\u52a8ML\u7684\u6700\u65b0\u6280\u672f\uff0c\u5f00\u53d1\u4eba\u5458\u53ef\u8f7b\u677e\u6784\u5efa\u548c\u90e8\u7f72ML\u9a71\u52a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 keras \u66f4\u9ad8\u7ea7\u7684 API\uff0c\u548c tensorflow \u8054\u5408\u4f7f\u7528\u5f88\u65b9\u4fbf\u3002\u6700\u65b0\u7684 TensorFlow 2.0 \u975e\u5e38\u63a8\u8350\u4f7f\u7528 Keras \u4f5c\u4e3a\u6a21\u578b\u642d\u5efa\u7684\u9ad8\u7ea7 API\uff0c\u4f60\u4e0d\u5fc5\u76f4\u63a5\u5b89\u88c5 Keras\uff0c\u76f4\u63a5\u4f7f\u7528 tf.keras \u5373\u53ef\u3002 Keras\u662f\u4e00\u4e2a\u9ad8\u7ea7\u795e\u7ecf\u7f51\u7edcAPI\uff0c\u7528Python\u7f16\u5199\uff0c\u80fd\u591f\u5728TensorFlow\uff0cCNTK\u6216Theano\u4e4b\u4e0a\u8fd0\u884c\u3002\u5b83\u7684\u5f00\u53d1\u91cd\u70b9\u662f\u5b9e\u73b0\u5feb\u901f\u5b9e\u9a8c\u3002\u80fd\u591f\u4ee5\u6700\u5c0f\u7684\u5ef6\u8fdf\u4ece\u7406\u5ff5\u5230\u7ed3\u679c\u662f\u8fdb\u884c\u826f\u597d\u7814\u7a76\u7684\u5173\u952e\u3002 \u7ed8\u5236\u6a21\u578b\u7ed3\u6784\u9700\u8981 graphviz \u548c pydot\u3002 tensorboard TensorBoard \u662f\u4e00\u4e2a\u53ef\u89c6\u5316\u5de5\u5177\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5b83\u53ef\u89c6\u5316\uff1a loss\u3001acc \u66f2\u7ebf \u6a21\u578b\u7ed3\u6784 \u6743\u91cd\u5206\u5e03 \u751f\u6210\u7684\u56fe\u50cf \u751f\u6210\u7684\u6587\u5b57 tensorboardX tensorboardX \u662f\u4e00\u4e2a\u6846\u67b6\u65e0\u5173\u7684 tensorboard writer\uff0c\u652f\u6301 numpy \u77e9\u9635\u3001pytorch \u7684 tensor \u7b49\u683c\u5f0f\u3002 \u76ee\u524d pytorch 1.1 \u4e5f\u6709 \u5b98\u65b9\u652f\u6301 \uff0c\u4f46\u662f\u529f\u80fd\u6709\u9650\uff0c\u6240\u4ee5\u76ee\u524d\u6211\u4ecd\u7136\u5728\u4f7f\u7528 tensorboardX\u3002","title":"Python \u73af\u5883"},{"location":"python-environment/#python","text":"\u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6765\u8bf4\uff0cPython \u662f\u5fc5\u4e0d\u53ef\u5c11\u7684\u5de5\u5177\uff0c\u56e0\u4e3a\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u90fd\u652f\u6301 Python\uff08\u6bd4\u5982 TensorFlow\u3001PyTorch\u3001MXNet \u7b49\uff09\u3002\u5728\u6a21\u578b\u5f00\u53d1\u9636\u6bb5\uff0c\u4f7f\u7528 Python \u975e\u5e38\u65b9\u4fbf\uff0c\u5982\u679c\u914d\u5408 Jupyter Notebook \u4f7f\u7528\uff0c\u8fd8\u53ef\u4ee5\u8fdb\u4e00\u6b65\u63d0\u5347\u5f00\u53d1\u6548\u7387\u3002","title":"Python \u73af\u5883"},{"location":"python-environment/#miniconda-bash","text":"\u4e0b\u8f7d \u6700\u65b0\u7684 miniconda \u5b89\u88c5\u5305\u3002 20230424 \u4e0b\u8f7d\u7684\u662f Miniconda3-latest-MacOSX-arm64.sh","title":"Miniconda bash \u5b89\u88c5"},{"location":"python-environment/#_1","text":"# bash \u5b89\u88c5\u5305\u8def\u5f84 bash /Users/lhy/Downloads/Miniconda3-latest-MacOSX-arm64.sh \u5b89\u88c5 Miniconda \u540e\uff0c\u4f1a\u81ea\u52a8\u5c06 Miniconda \u7684\u8def\u5f84\u6dfb\u52a0\u5230\u73af\u5883\u53d8\u91cf\u4e2d\uff0c\u4f46\u662f\u9700\u8981\u5173\u95ed\u5e76\u91cd\u65b0\u6253\u5f00 shell \u624d\u80fd\u751f\u6548\u3002 \u5982\u679c\u9700\u8981\u5728\u5f53\u524d\u7ec8\u7aef\u4f1a\u8bdd\u4e2d\u7acb\u5373\u751f\u6548\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\uff1a source ~/.zshrc","title":"\u547d\u4ee4\u884c\u5b89\u88c5"},{"location":"python-environment/#miniconda-brew","text":"","title":"Miniconda brew \u5b89\u88c5"},{"location":"python-environment/#_2","text":"brew install --cask miniconda \u6b64\u65f6\uff0cconda \u4f1a\u5b89\u88c5\u5728\u8fd9\u4e2a\u8def\u5f84\u4e0b /opt/homebrew/bin/conda \u3002","title":"\u547d\u4ee4\u884c\u5b89\u88c5"},{"location":"python-environment/#miniconda","text":"conda --version","title":"\u68c0\u67e5 miniconda \u662f\u5426\u5b89\u88c5\u6210\u529f"},{"location":"python-environment/#miniconda_1","text":"rm -rf conda","title":"\u5378\u8f7d miniconda"},{"location":"python-environment/#anaconda","text":"Anaconda \u662f\u4e00\u4e2a Pyhton \u7684\u5305\u7ba1\u7406\u5668\uff0c\u5b83\u53ef\u4ee5\u7b80\u5316 Python \u73af\u5883\u7684\u5b89\u88c5\u3002\u7531\u4e8e Ubuntu \u7cfb\u7edf\u3001macOS \u7cfb\u7edf\u7684\u5c40\u9650\u6027\uff0c\u6211\u4eec\u5c3d\u91cf\u4e0d\u8981\u5728\u7cfb\u7edf\u81ea\u5e26\u7684\u73af\u5883\u91cc\u5b89\u88c5\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u4e0d\u7136\u53ef\u80fd\u4f1a\u51fa\u73b0\u4e00\u4e9b\u4e0d\u53ef\u9884\u6599\u7684\u95ee\u9898\u3002 Anaconda \u4e2d\u7684 numpy\u3001scikit-learn \u7b49\u5e93\u4f7f\u7528\u4e86 Intel MKL \u8fdb\u884c\u52a0\u901f\uff0c\u7406\u8bba\u4e0a\u4f1a\u6bd4 pip \u76f4\u63a5\u5b89\u88c5\u7684\u7248\u672c\u901f\u5ea6\u5feb\u3002 Anaconda \u4e0d\u9700\u8981 root \u6743\u9650\uff0c\u6240\u4ee5\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u5b89\u88c5\u5728\u7528\u6237\u76ee\u5f55\u4e0b\uff0c\u53ea\u8981\u914d\u7f6e\u597d\u73af\u5883\u53d8\u91cf\u5373\u53ef\u4f7f\u7528\uff0c\u5f53\u4f60\u4e0d\u9700\u8981\u5b83\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u76f4\u63a5\u5220\u9664\u5b83\u7684\u76ee\u5f55\uff0c\u7136\u540e\u5c06\u5bf9\u5e94\u7684\u73af\u5883\u53d8\u91cf\u4e00\u8d77\u5220\u9664\u5373\u53ef\u3002 \u4f60\u53ef\u4ee5\u76f4\u63a5 rsync \u6574\u4e2a anaconda \u6587\u4ef6\u5939\u5230\u5176\u4ed6\u76f8\u540c\u786c\u4ef6\u548c\u7cfb\u7edf\u73af\u5883\u7684\u673a\u5668\u4e0a\uff0c\u5b83\u4eec\u7684 Python \u73af\u5883\u53ef\u4ee5\u4fdd\u6301\u7edd\u5bf9\u7684\u7edf\u4e00\uff0c\u5728\u505a\u5206\u5e03\u5f0f\u5e76\u884c\u8bad\u7ec3\u7684\u65f6\u5019\u975e\u5e38\u6709\u7528\u3002","title":"Anaconda"},{"location":"python-environment/#anaconda_1","text":"Anaconda \u5b98\u65b9\u4e0b\u8f7d\u9875\u9762\uff1a https://www.anaconda.com/downloads \u4f60\u53ea\u9700\u8981\u4e0b\u8f7d\u5bf9\u5e94\u7cfb\u7edf\u7684\u5b89\u88c5\u5305\uff0c\u7136\u540e\u76f4\u63a5\u8fd0\u884c\u5b89\u88c5\u5305\u5373\u53ef\u3002","title":"\u5b89\u88c5 Anaconda"},{"location":"python-environment/#_3","text":"\u5728 macOS \u4e0a\u5b89\u88c5 Anaconda \u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a wget https://repo.anaconda.com/archive/Anaconda3-2020.02-MacOSX-x86_64.sh bash Anaconda3-2020.02-MacOSX-x86_64.sh \u9700\u8981\u4f7f\u7528 brew \u5b89\u88c5 wget \u547d\u4ee4 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf \uff0c\u5982 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.02-MacOSX-x86_64.sh","title":"\u547d\u4ee4\u884c\u5b89\u88c5"},{"location":"python-environment/#brew-cask","text":"macOS \u4e0a\u8fd8\u53ef\u4ee5 \u4f7f\u7528 brew cask \u5b89\u88c5 \uff1a brew cask install Anaconda","title":"brew cask \u5b89\u88c5"},{"location":"python-environment/#_4","text":"\u5b89\u88c5\u597d\u4ee5\u540e\uff0c\u6709\u53ef\u80fd\u9700\u8981\u624b\u52a8 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f zsh\uff0c\u4f60\u9700\u8981\u4e3a zsh \u521d\u59cb\u5316\uff1a /usr/local/anaconda3/bin/conda init zsh \u6267\u884c\u4ee5\u540e\uff0c\u5728 ~/.zshrc \u4e2d\u53ef\u4ee5\u770b\u5230\u4e0b\u9762\u7684\u5185\u5bb9\uff1a # >>> conda initialize >>> # !! Contents within this block are managed by 'conda init' !! __conda_setup = \" $( '/home/ypw/anaconda3/bin/conda' 'shell.zsh' 'hook' 2 > /dev/null ) \" if [ $? -eq 0 ] ; then eval \" $__conda_setup \" else if [ -f \"/home/ypw/anaconda3/etc/profile.d/conda.sh\" ] ; then . \"/home/ypw/anaconda3/etc/profile.d/conda.sh\" else export PATH = \"/home/ypw/anaconda3/bin: $PATH \" fi fi unset __conda_setup # <<< conda initialize <<<","title":"\u914d\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"python-environment/#anaconda-python","text":"\u5982\u679c\u6211\u4eec\u9700\u8981\u5176\u4ed6 Python \u73af\u5883\uff0c\u53ef\u4ee5\u4f7f\u7528 conda \u521b\u5efa\uff1a conda create -n python2 python = 2 .7 source activate python2 \u53c2\u8003\u94fe\u63a5\uff1a https://conda.io/docs/user-guide/tasks/manage-environments.html","title":"\u4f7f\u7528 Anaconda \u521b\u5efa\u5176\u4ed6 Python \u73af\u5883"},{"location":"python-environment/#conda-python-jupyter","text":"\u5f53\u4f60\u5e0c\u671b\u5728 jupyter \u91cc\u4f7f\u7528\u4f60\u7684\u865a\u62df\u73af\u5883\u7684\u65f6\u5019\uff0c\u4f60\u9700\u8981\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a conda activate python2 conda install ipykernel python - m ipykernel install -- user -- name python2 -- display - name \"Python 2\" \u5176\u4e2d\u7684 python2 \u662f\u4f60\u7684\u865a\u62df\u73af\u5883\u7684\u540d\u5b57\uff0cdisplay-name \u53ef\u4ee5\u53d6\u4e00\u4e2a\u597d\u542c\u7684\u540d\u5b57\uff0c\u5b83\u4f1a\u5728 jupyter notebook \u5207\u6362 kernel \u7684\u5730\u65b9\u663e\u793a\u3002 \u53c2\u8003\u94fe\u63a5\uff1a https://ipython.readthedocs.io/en/stable/install/kernel_install.html","title":"\u628a Conda \u7684 Python \u73af\u5883\u6dfb\u52a0\u5230 jupyter \u91cc"},{"location":"python-environment/#anaconda_2","text":"\u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528 \u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf \uff1a nano ~/.condarc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r custom_channels: conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud","title":"\u5207\u6362 anaconda \u6e90"},{"location":"python-environment/#pip","text":"\u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528\u963f\u91cc\u4e91\u7684\u955c\u50cf\uff1a pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ \u5e38\u7528 pypi \u955c\u50cf\uff1a https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ https://mirrors.163.com/pypi/simple/ https://pypi.doubanio.com/simple/ https://mirrors.ustc.edu.cn/pypi/web/simple/","title":"\u5207\u6362 pip \u6e90"},{"location":"python-environment/#python_1","text":"\u4e0b\u9762\u662f\u6211\u8ba4\u4e3a\u6bd4\u8f83\u91cd\u8981\u7684 Python \u5e93\uff1a jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow keras tensorboard tensorboardx \u5b89\u88c5\u5927\u793c\u5305\uff1a pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow keras tensorboardx xlrd openpyxl","title":"Python \u5e93"},{"location":"python-environment/#jupyter","text":"\u5728\u5b9e\u9a8c\u9636\u6bb5\uff0c\u5f3a\u70c8\u5efa\u8bae\u4f60\u4f7f\u7528 jupyter notebook \u7f16\u5199\u5b9e\u9a8c\u4ee3\u7801\uff0c\u56e0\u4e3a\u5b83\u4e0e\u5199 Python \u811a\u672c\u7684\u903b\u8f91\u5b8c\u5168\u4e0d\u540c\u3002 \u5b98\u65b9\u4ecb\u7ecd\uff1a Jupyter Notebook\u662f\u4e00\u4e2a\u5f00\u6e90Web\u5e94\u7528\u7a0b\u5e8f\uff0c\u5141\u8bb8\u60a8\u521b\u5efa\u548c\u5171\u4eab\u5305\u542b\u5b9e\u65f6\u4ee3\u7801\uff0c\u516c\u5f0f\uff0c\u53ef\u89c6\u5316\u548c\u53d9\u8ff0\u6587\u672c\u7684\u6587\u6863\u3002\u7528\u9014\u5305\u62ec\uff1a\u6570\u636e\u6e05\u7406\u548c\u8f6c\u6362\uff0c\u6570\u503c\u6a21\u62df\uff0c\u7edf\u8ba1\u5efa\u6a21\uff0c\u6570\u636e\u53ef\u89c6\u5316\uff0c\u673a\u5668\u5b66\u4e60\u7b49\u3002 \u7279\u70b9\uff1a web\u9875\u9762\u4ea4\u4e92\uff0c\u5728\u5404\u4e2a\u5e73\u53f0\u751a\u81f3\u662f\u624b\u673a\u4e0a\u90fd\u6709\u540c\u6837\u7684\u754c\u9762 \u8fd0\u884c\u8fc7\u7684\u4ee3\u7801\u4ea7\u751f\u7684\u53d8\u91cf\u3001\u51fd\u6570\u3001\u7c7b\u4e0d\u4f1a\u6d88\u5931\uff0c\u9664\u975e\u4f60\u91cd\u542f\u5185\u6838 \u4e0d\u4ec5\u652f\u6301\u5199\u4ee3\u7801\uff0c\u663e\u793a\u51fd\u6570\u8f93\u51fa\u7684\u6587\u5b57\uff0c\u8fd8\u652f\u6301\u663e\u793a\u56fe\u7247\uff0c\u751a\u81f3\u5b9e\u73b0\u7b80\u5355\u7684\u4ea4\u4e92\u529f\u80fd \u652f\u6301 Markdown \u7f16\u5199\u6ce8\u91ca\uff0c\u8fd8\u652f\u6301 latex \u516c\u5f0f","title":"jupyter"},{"location":"python-environment/#jupyter_contrib_nbextensions","text":"Jupyter Notebook \u63d2\u4ef6\u3002 \u8be5 jupyter_contrib_nbextensions \u8f6f\u4ef6\u5305\u5305\u542b\u4e00\u7cfb\u5217\u793e\u533a\u8d21\u732e\u7684\u975e\u5b98\u65b9\u6269\u5c55\uff0c\u53ef\u4e3aJupyter\u7b14\u8bb0\u672c\u6dfb\u52a0\u529f\u80fd\u3002\u8fd9\u4e9b\u6269\u5c55\u5927\u591a\u662f\u7528Javascript\u7f16\u5199\u7684\uff0c\u5c06\u5728\u60a8\u7684\u6d4f\u89c8\u5668\u4e2d\u672c\u5730\u52a0\u8f7d\u3002 \u6211\u4f7f\u7528\u4e86 \u4ee3\u7801\u6267\u884c\u65f6\u95f4\u63d2\u4ef6 \u548c \u51fd\u6570\u6298\u53e0\u63d2\u4ef6 \u3002","title":"jupyter_contrib_nbextensions"},{"location":"python-environment/#numpy","text":"\u79d1\u5b66\u8ba1\u7b97\u5fc5\u5907\u5e93\u3002 NumPy\u662fPython\u8bed\u8a00\u7684\u4e00\u4e2a\u6269\u5c55\u7a0b\u5e8f\u5e93\u3002\u652f\u6301\u9ad8\u7aef\u5927\u91cf\u7684\u7ef4\u5ea6\u6570\u7ec4\u4e0e\u77e9\u9635\u8fd0\u7b97\uff0c\u6b64\u5916\u4e5f\u9488\u5bf9\u6570\u7ec4\u8fd0\u7b97\u63d0\u4f9b\u5927\u91cf\u7684\u6570\u5b66\u51fd\u6570\u5e93\u3002","title":"numpy"},{"location":"python-environment/#pandas","text":"\u64cd\u4f5c csv \u975e\u5e38\u65b9\u4fbf\uff0cpython \u91cc\u7684 excel\u3002 _pandas_\u662f\u4e00\u4e2a\u5f00\u6e90\u7684\uff0cBSD\u8bb8\u53ef\u7684\u5e93\uff0c\u4e3aPython\u7f16\u7a0b\u8bed\u8a00\u63d0\u4f9b\u9ad8\u6027\u80fd\uff0c\u6613\u4e8e\u4f7f\u7528\u7684\u6570\u636e\u7ed3\u6784\u548c\u6570\u636e\u5206\u6790\u5de5\u5177\u3002","title":"pandas"},{"location":"python-environment/#scikit-learn","text":"\u673a\u5668\u5b66\u4e60\u6a21\u578b\u5927\u5168\u3002 Python\u4e2d\u7684\u673a\u5668\u5b66\u4e60 \u7b80\u5355\u6709\u6548\u7684\u6570\u636e\u6316\u6398\u548c\u6570\u636e\u5206\u6790\u5de5\u5177 \u53ef\u4f9b\u6240\u6709\u4eba\u8bbf\u95ee\uff0c\u5e76\u53ef\u5728\u5404\u79cd\u73af\u5883\u4e2d\u91cd\u590d\u4f7f\u7528 \u57fa\u4e8eNumPy\uff0cSciPy\u548cmatplotlib\u6784\u5efa \u5f00\u6e90\uff0c\u5546\u4e1a\u4e0a\u53ef\u7528 - BSD\u8bb8\u53ef\u8bc1 \u6ce8\u610f\u5b89\u88c5\u7684\u65f6\u5019\u4e0d\u662f sklearn\uff0c\u800c\u662f scikit-learn\uff1a pip install scikit - learn","title":"scikit-learn"},{"location":"python-environment/#matplotlib","text":"\u753b\u56fe\u5de5\u5177\u3002 Matplotlib\u662f\u4e00\u4e2aPython 2D\u7ed8\u56fe\u5e93\uff0c\u53ef\u4ee5\u751f\u6210\u5404\u79cd\u786c\u62f7\u8d1d\u683c\u5f0f\u548c\u8de8\u5e73\u53f0\u7684\u4ea4\u4e92\u5f0f\u73af\u5883\u7684\u51fa\u7248\u7269\u8d28\u91cf\u6570\u636e\u3002Matplotlib\u53ef\u7528\u4e8ePython\u811a\u672c\u3001IPython shell\u3001Jupyter Notebook \u548c Web\u5e94\u7528\u7a0b\u5e8f\u670d\u52a1\u5668\u548c\u56db\u4e2a\u56fe\u5f62\u7528\u6237\u754c\u9762\u5de5\u5177\u5305\u3002","title":"matplotlib"},{"location":"python-environment/#opencv-python","text":"OpenCV \u7684 Python \u5e93\uff0c\u56fe\u50cf\u5904\u7406\u5fc5\u5907\u3002\u6ce8\u610f\u8fd9\u4e0d\u662f\u5b98\u65b9\u7684\u5e93\uff0c\u800c\u662f\u7b2c\u4e09\u65b9\u7f16\u8bd1\u7684\u5e93\u3002 OpenCV\u7684\u5168\u79f0\u662fOpen Source Computer Vision Library\uff0c\u662f\u4e00\u4e2a\u8de8\u5e73\u53f0\u7684\u8ba1\u7b97\u673a\u89c6\u89c9\u5e93\u3002 \u5b98\u65b9\u5efa\u8bae\u662f\u4ece\u6e90\u7801\u7f16\u8bd1\uff1a https://docs.opencv.org/3.4.6/d2/de6/tutorial_py_setup_in_ubuntu.html \u5982\u679c\u4f60\u4f7f\u7528\u7684\u529f\u80fd\u4e0d\u662f\u5f88\u590d\u6742\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 pip \u5b89\u88c5 opencv-python \u3002\u5982\u679c\u4f60\u4f7f\u7528\u4e86 opencv-contrib \u91cc\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u5b89\u88c5 opencv-contrib-python \u3002","title":"opencv-python"},{"location":"python-environment/#pillow","text":"PIL\uff0c\u53e6\u4e00\u4e2a\u56fe\u50cf\u5904\u7406\u5e93\uff0cPyTorch \u91cc\u7684 torchvision \u6709\u5f88\u591a\u5199\u597d\u7684\u6570\u636e\u589e\u5f3a\u7c7b\uff0c\u5b83\u4eec\u7684\u8f93\u5165\u7c7b\u578b\u662f PIL.Image\u3002 \u8be5\u5e93\u63d0\u4f9b\u5e7f\u6cdb\u7684\u6587\u4ef6\u683c\u5f0f\u652f\u6301\uff0c\u9ad8\u6548\u7684\u5185\u90e8\u8868\u793a\u548c\u76f8\u5f53\u5f3a\u5927\u7684\u56fe\u50cf\u5904\u7406\u529f\u80fd\u3002 \u6838\u5fc3\u56fe\u50cf\u5e93\u65e8\u5728\u5feb\u901f\u8bbf\u95ee\u4ee5\u51e0\u79cd\u57fa\u672c\u50cf\u7d20\u683c\u5f0f\u5b58\u50a8\u7684\u6570\u636e\u3002\u5b83\u5e94\u8be5\u4e3a\u4e00\u822c\u7684\u56fe\u50cf\u5904\u7406\u5de5\u5177\u63d0\u4f9b\u575a\u5b9e\u7684\u57fa\u7840\u3002","title":"pillow"},{"location":"python-environment/#tqdm","text":"\u8fdb\u5ea6\u6761\u5e93\uff0c\u8017\u65f6\u957f\u7684\u4efb\u52a1\u53ef\u4ee5\u4f7f\u7528 tqdm \u76f4\u89c2\u5730\u5c55\u793a\u4efb\u52a1\u7684\u8fdb\u5ea6\uff0c\u907f\u514d\u7126\u8651\u3002 tqdm \u5728\u963f\u62c9\u4f2f\u8bed\u4e2d\u662f\u201c\u8fdb\u6b65\u201d\uff08 taqadum \uff0c\u062a\u0642\u062f\u0645\uff09\u7684\u610f\u601d\uff0c\u5728\u897f\u73ed\u7259\u8bed\u4e2d\u662f\u201c\u6211\u592a\u7231\u4f60\u4e86\u201d\uff08 te quiero demasiado \uff09\u7684\u7f29\u5199\u3002 \u53ea\u9700\u5728\u4efb\u4f55\u8fed\u4ee3\u5668\u5916\u5305\u4e00\u4e2a tqdm\uff1a tqdm(iterable) \uff0c\u5c31\u80fd\u7acb\u523b\u8ba9\u4f60\u7684\u5faa\u73af\u663e\u793a\u4e00\u4e2a\u806a\u660e\u7684\u8fdb\u5ea6\u6761\uff01","title":"tqdm"},{"location":"python-environment/#torch","text":"\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u63a8\u8350\u4f7f\u7528\u3002 \u4e00\u4e2a\u5f00\u6e90\u6df1\u5ea6\u5b66\u4e60\u5e73\u53f0\uff0c\u63d0\u4f9b\u4ece\u7814\u7a76\u539f\u578b\u5230\u751f\u4ea7\u90e8\u7f72\u7684\u65e0\u7f1d\u8def\u5f84\u3002","title":"torch"},{"location":"python-environment/#torchvision","text":"\u548c PyTorch \u914d\u5957\u4f7f\u7528\u3002 torchvision \u5305\u542b\u4e86\u6d41\u884c\u7684\u6570\u636e\u96c6\uff0c\u9884\u8bad\u7ec3\u6a21\u578b\u548c\u8ba1\u7b97\u673a\u89c6\u89c9\u7684\u5e38\u89c1\u7684\u56fe\u50cf\u53d8\u6362\u3002","title":"torchvision"},{"location":"python-environment/#tensorflow","text":"\u6df1\u5ea6\u5b66\u4e60\u5e93\uff0c\u5927\u800c\u5168\u3002\u914d\u5907\u663e\u5361\u7684\u673a\u5668\u8bf7\u6309\u7167 Ubuntu \u73af\u5883 \u8fdb\u884c\u914d\u7f6e\u3002 TensorFlow\u662f\u4e00\u4e2a\u7528\u4e8e\u673a\u5668\u5b66\u4e60\u7684\u7aef\u5230\u7aef\u5f00\u6e90\u5e73\u53f0\u3002 \u5b83\u62e5\u6709\u5168\u9762\u3001\u7075\u6d3b\u7684\u5de5\u5177\u3001\u5e93\u548c\u793e\u533a\u8d44\u6e90\u751f\u6001\u7cfb\u7edf\uff0c\u53ef\u8ba9\u7814\u7a76\u4eba\u5458\u63a8\u52a8ML\u7684\u6700\u65b0\u6280\u672f\uff0c\u5f00\u53d1\u4eba\u5458\u53ef\u8f7b\u677e\u6784\u5efa\u548c\u90e8\u7f72ML\u9a71\u52a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002","title":"tensorflow"},{"location":"python-environment/#keras","text":"\u66f4\u9ad8\u7ea7\u7684 API\uff0c\u548c tensorflow \u8054\u5408\u4f7f\u7528\u5f88\u65b9\u4fbf\u3002\u6700\u65b0\u7684 TensorFlow 2.0 \u975e\u5e38\u63a8\u8350\u4f7f\u7528 Keras \u4f5c\u4e3a\u6a21\u578b\u642d\u5efa\u7684\u9ad8\u7ea7 API\uff0c\u4f60\u4e0d\u5fc5\u76f4\u63a5\u5b89\u88c5 Keras\uff0c\u76f4\u63a5\u4f7f\u7528 tf.keras \u5373\u53ef\u3002 Keras\u662f\u4e00\u4e2a\u9ad8\u7ea7\u795e\u7ecf\u7f51\u7edcAPI\uff0c\u7528Python\u7f16\u5199\uff0c\u80fd\u591f\u5728TensorFlow\uff0cCNTK\u6216Theano\u4e4b\u4e0a\u8fd0\u884c\u3002\u5b83\u7684\u5f00\u53d1\u91cd\u70b9\u662f\u5b9e\u73b0\u5feb\u901f\u5b9e\u9a8c\u3002\u80fd\u591f\u4ee5\u6700\u5c0f\u7684\u5ef6\u8fdf\u4ece\u7406\u5ff5\u5230\u7ed3\u679c\u662f\u8fdb\u884c\u826f\u597d\u7814\u7a76\u7684\u5173\u952e\u3002 \u7ed8\u5236\u6a21\u578b\u7ed3\u6784\u9700\u8981 graphviz \u548c pydot\u3002","title":"keras"},{"location":"python-environment/#tensorboard","text":"TensorBoard \u662f\u4e00\u4e2a\u53ef\u89c6\u5316\u5de5\u5177\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5b83\u53ef\u89c6\u5316\uff1a loss\u3001acc \u66f2\u7ebf \u6a21\u578b\u7ed3\u6784 \u6743\u91cd\u5206\u5e03 \u751f\u6210\u7684\u56fe\u50cf \u751f\u6210\u7684\u6587\u5b57","title":"tensorboard"},{"location":"python-environment/#tensorboardx","text":"tensorboardX \u662f\u4e00\u4e2a\u6846\u67b6\u65e0\u5173\u7684 tensorboard writer\uff0c\u652f\u6301 numpy \u77e9\u9635\u3001pytorch \u7684 tensor \u7b49\u683c\u5f0f\u3002 \u76ee\u524d pytorch 1.1 \u4e5f\u6709 \u5b98\u65b9\u652f\u6301 \uff0c\u4f46\u662f\u529f\u80fd\u6709\u9650\uff0c\u6240\u4ee5\u76ee\u524d\u6211\u4ecd\u7136\u5728\u4f7f\u7528 tensorboardX\u3002","title":"tensorboardX"},{"location":"remote-debugging-with-pycharm/","text":"\u5982\u4f55\u4f7f\u7528 PyCharm \u8fdc\u7a0b\u8c03\u8bd5 https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html","title":"\u5982\u4f55\u4f7f\u7528 PyCharm \u8fdc\u7a0b\u8c03\u8bd5"},{"location":"remote-debugging-with-pycharm/#pycharm","text":"https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html","title":"\u5982\u4f55\u4f7f\u7528 PyCharm \u8fdc\u7a0b\u8c03\u8bd5"},{"location":"ubuntu-environment/","text":"Ubuntu \u73af\u5883 CUDA \u6700\u65b0\u7248\uff1a https://developer.nvidia.com/cuda-downloads CUDA 11.3\uff1a https://developer.nvidia.com/cuda-11-3-1-download-archive CUDA 10.2\uff1a https://developer.nvidia.com/cuda-10.2-download-archive CUDA 10.1\uff1a https://developer.nvidia.com/cuda-10.1-download-archive-update2 CUDA 10.0\uff1a https://developer.nvidia.com/cuda-10.0-download-archive \u65e7\u7248\u5217\u8868\uff1a https://developer.nvidia.com/cuda-toolkit-archive CUDA \u662f\u82f1\u4f1f\u8fbe\u663e\u5361\u8fdb\u884c\u5404\u79cd\u9ad8\u6027\u80fd\u8fd0\u7b97\u5fc5\u5907\u7684\u5e93\uff0c\u4e0d\u540c\u8f6f\u4ef6\u5305\u4f9d\u8d56\u7684 CUDA \u7248\u672c\u53ef\u80fd\u4e0d\u540c\uff0c\u4f60\u9700\u8981\u6839\u636e\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u9009\u62e9\u5408\u9002\u7684 CUDA \u548c cuDNN \u7248\u672c\u3002 \u7248\u672c Windows 10 Linux CUDA 11.3 cuda_11.3.1_465.89_win10.exe cuda_11.3.1_465.19.01_linux.run CUDA 10.2 cuda_10.2.89_441.22_win10.exe cuda_10.2.89_440.33.01_linux.run CUDA 10.1 cuda_10.1.243_426.00_win10.exe cuda_10.1.243_418.87.00_linux.run CUDA 10.0 cuda_10.0.130_411.31_win10.exe cuda_10.0.130_410.48_linux.run \u4ee5\u4e0b\u7248\u672c\u8f83\u4f4e\uff0c\u63a8\u8350\u4f7f\u7528\u4e0a\u9762\u7684\u7248\u672c\u3002 CUDA 9.2 cuda_9.2.148_win10.exe cuda_9.2.148_396.37_linux.run CUDA 9.1 cuda_9.1.85_win10.exe cuda_9.1.85_387.26_linux.run CUDA 9.0 cuda_9.0.176_win10.exe cuda_9.0.176_384.81_linux.run CUDA 8.0 GA2 cuda_8.0.61_win10.exe cuda_8.0.61_375.26_linux.run CUDA 8.0 GA1 cuda_8.0.44_win10.exe cuda_8.0.44_linux.run CUDA 7.5 cuda_7.5.18_win10.exe cuda_7.5.18_linux.run CUDA 7.0 cuda_7.0.28_windows.exe cuda_7.0.28_linux.run CUDA 6.5 cuda_6.5.14_windows_general_64.exe cuda_6.5.14_linux_64.run cuDNN cuDNN \u4e0b\u8f7d\u9700\u8981\u6ce8\u518c\uff0c\u5730\u5740\u5982\u4e0b\uff1a \u6700\u65b0\u7248\uff1a https://developer.nvidia.com/cudnn \u65e7\u7248\uff1a https://developer.nvidia.com/rdp/cudnn-archive cuDNN \u662f\u82f1\u4f1f\u8fbe\u63a8\u51fa\u7684\u4e13\u95e8\u7528\u4e8e\u6df1\u5ea6\u5b66\u4e60\u52a0\u901f\u8ba1\u7b97\u7684\u5e93\uff0c\u4e00\u822c\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u4f1a\u4f7f\u7528 cuDNN\u3002 \u4f60\u9700\u8981\u6839\u636e\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u9009\u62e9\u5408\u9002\u7684 CUDA \u548c cuDNN \u7248\u672c\u3002 \u4e0b\u8868\u662f\u5e38\u89c1\u7248\u672c\u7684 cuDNN Linux \u4e0b\u8f7d\u94fe\u63a5\uff1a cuDNN CUDA9.0 CUDA10.0 CUDA10.2 CUDA11.2 CUDA11.3 8.2.1 - - cudnn-10.2-linux-x64-v8.2.1.32.tgz (959.98MB) - cudnn-11.3-linux-x64-v8.2.1.32.tgz (1.75GB) 8.1.0 - - cudnn-10.2-linux-x64-v8.1.0.77.tgz (720.54MB) cudnn-11.2-linux-x64-v8.1.0.77.tgz (1.23GB) - 7.4.1 cudnn-9.0-linux-x64-v7.4.1.5.tgz (347.17MB) cudnn-10.0-linux-x64-v7.4.1.5.tgz (403.12MB) - - - 7.2.1 cudnn-9.0-linux-x64-v7.2.1.38.tgz (331.19MB) - - - - 7.1.4 cudnn-9.0-linux-x64-v7.1.tgz (390.26MB) - - - - \u4e0b\u8868\u662f\u5e38\u89c1\u7248\u672c\u7684 cuDNN Windows \u4e0b\u8f7d\u94fe\u63a5\uff1a cuDNN CUDA9.0 CUDA10.0 CUDA10.2 CUDA11.2 CUDA11.3 8.2.1 - - cudnn-10.2-windows10-x64-v8.2.1.32.zip (392.82MB) - - 8.1.0 - - cudnn-10.2-windows10-x64-v8.1.0.77.zip (358.77MB) - - 7.4.1 cudnn-9.0-windows10-x64-v7.4.1.5.zip (179.09MB) cudnn-10.0-windows10-x64-v7.4.1.5.zip (208.93MB) - - - 7.2.1 cudnn-9.0-windows10-x64-v7.2.1.38.zip (171.64MB) - - - - 7.1.4 cudnn-9.0-windows10-x64-v7.1.zip (201.39MB) - - - - TensorRT TensorRT \u662f\u82f1\u4f1f\u8fbe\u63a8\u51fa\u7684\u63a8\u65ad\u5e93\uff08Inference\uff09\uff0c\u901a\u5e38\u7528\u4e8e\u6a21\u578b\u90e8\u7f72\u3002 \u4f7f\u7528 TensorRT \u53ef\u4ee5\u8fdb\u884c\u534a\u7cbe\u5ea6\u63a8\u65ad\uff0c\u751a\u81f3\u5bf9\u6a21\u578b\u8fdb\u884c int8 \u91cf\u5316\uff0c\u4ece\u800c\u5f97\u5230\u6570\u500d\u7684\u6027\u80fd\u63d0\u5347\uff0c\u5e76\u4e14\u5c3d\u53ef\u80fd\u4fdd\u8bc1\u7cbe\u5ea6\u3002\u7531\u4e8e\u6b64\u9879\u76ee\u8fd8\u5728\u5f00\u53d1\u9636\u6bb5\uff0c\u4e0d\u540c\u7684\u7248\u672c\u53ef\u80fd\u4e0d\u901a\u7528\uff0c\u8bf7\u53c2\u8003\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u6587\u6863\uff0c\u627e\u5230\u4f60\u6240\u9700\u8981\u5b89\u88c5\u7684 TensorRT \u7248\u672c\u3002 TensorFlow \u5b89\u88c5\u6559\u7a0b\uff1a https://www.tensorflow.org/install/gpu \u6700\u65b0\u7248\u7684 TensorFlow 1.14.0 \u4f9d\u8d56 CUDA 10.0\uff0c\u5e76\u4e14 cuDNN \u9700\u8981 7.4.1 \u6216\u66f4\u9ad8\u7684\u7248\u672c\uff0cNVIDIA \u9a71\u52a8\u9700\u8981 410.x \u6216\u66f4\u9ad8\u7248\u672c\u3002 \u5386\u53f2\u7248\u672c\u4f9d\u8d56\u73af\u5883 TensorFlow CUDA cuDNN NVIDIA Driver NCCL TensorRT 1.14 10.0 7.4.1 410 2.2 5.0 1.13 10.0 7.4.1 410 2.2 5.0 1.12 9.0 7.2 384 2.2 4.0 1.11 9.0 7.2 384 2.2 4.0 1.10 9.0 7.1 384 2.2 4.0 1.9 9.0 7.0 3.0 1.8 9.0 7.0 3.0 1.7 9.0 7.0 3.0 1.6 9.0 7.0 1.5 9.0 7.0 1.4 8.0 6.0 1.3 8.0 6.0 1.2 8.0 5.1 1.1 8.0 5.1 1.0 8.0 5.1 \u63d0\u793a\uff1a NVIDIA Driver \u4e3a\u7a7a\uff0c\u5b98\u65b9\u6587\u6863\u8bf4\u7684\u662f\u53ea\u8981\u5b89\u88c5\u6ee1\u8db3 CUDA \u7248\u672c\u7684\u9a71\u52a8\u5373\u53ef NCCL \u548c TensorRT \u4e3a\u7a7a\uff0c\u8868\u793a\u4e0d\u9700\u8981\u5b89\u88c5 PyTorch PyTorch \u81ea\u5e26 CUDA \u548c cuDNN\uff0c\u53ea\u9700\u8981\u5b89\u88c5 NVIDIA \u9a71\u52a8\u5373\u53ef\u8fd0\u884c\u3002 \u76ee\u524d PyPI \u5b89\u88c5\u7684 PyTorch \u4f7f\u7528\u7684\u662f CUDA9.0\uff0c\u5982\u679c\u4f60\u9700\u8981\u5176\u4ed6\u7248\u672c\uff0c\u8bf7\u4f7f\u7528\u5b98\u7f51\u4e0a\u7684\u9009\u62e9\u5668\u627e\u5230\u4f60\u9700\u8981\u7684\u7248\u672c\uff0c\u6bd4\u5982 Python 3.7 \u5b89\u88c5 CUDA10 \u7684 PyTorch \u9700\u8981\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a pip3 install https://download.pytorch.org/whl/cu100/torch-1.1.0-cp37-cp37m-linux_x86_64.whl pip3 install https://download.pytorch.org/whl/cu100/torchvision-0.3.0-cp37-cp37m-linux_x86_64.whl \u5fc5\u5907\u547d\u4ee4 sudo apt install -y git curl htop nload tmux screen aria2 graphviz aptitude tree iotop \u5e38\u89c1\u7684 git\u3001htop\u3001nload \u7b49\u547d\u4ee4\u5728 macOS \u73af\u5883 \u91cc\u5df2\u7ecf\u4ecb\u7ecd\u8fc7\u4e86\u3002\u5176\u5b9e\u5927\u90e8\u5206\u547d\u4ee4\u5728\u6ca1\u6709\u5b89\u88c5\u7684\u65f6\u5019\uff0c\u5982\u679c\u4f60\u4f7f\u7528\u5b83\u4eec\uff0c\u4f1a\u81ea\u52a8\u63d0\u793a\u9700\u8981\u5b89\u88c5\uff0c\u6240\u4ee5\u4e0d\u7528\u62c5\u5fc3\u6ca1\u6709\u5b89\u88c5\u5168\uff1a ypw@ypw-ubuntu:~$ screen Command 'screen' not found, but can be installed with: sudo apt install screen curl curl \u662f\u4e00\u4e2a\u591a\u529f\u80fd\u7684\u7f51\u7edc\u64cd\u4f5c\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u53d1\u9001 GET\u3001POST \u8bf7\u6c42\u3002 \u5728\u5f00\u53d1\u670d\u52a1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4f1a\u7ecf\u5e38\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\u6765\u6d4b\u8bd5\u670d\u52a1\u662f\u5426\u80fd\u8fd4\u56de\u9884\u671f\u7684\u7ed3\u679c\u3002 GET\uff1a curl https://dl.ypw.io POST\uff1a curl -d \"param1=value1¶m2=value2\" -X POST http://localhost:3000/data POST json\uff1a curl -d '{\"key1\":\"value1\", \"key2\":\"value2\"}' -H \"Content-Type: application/json\" -X POST http://localhost:3000/data tmux tmux \u6700\u5927\u7684\u597d\u5904\u662f\u53ef\u4ee5\u8ba9\u4f60\u7684\u547d\u4ee4\u5728\u540e\u53f0\u8fd0\u884c\uff0c\u4e0d\u4f1a\u56e0\u4e3a\u7ec8\u7aef\u5173\u95ed\u800c\u9000\u51fa\u3002\u6bd4\u5982\u5728\u540e\u53f0\u8fd0\u884c jupyter\u3001python \u6570\u636e\u9884\u5904\u7406\u811a\u672c\u548c\u8bad\u7ec3\u811a\u672c\u7b49\u3002 tmux \u662f\u4e00\u4e2a\u4f18\u79c0\u7684\u7ec8\u7aef\u590d\u7528\u5668\u547d\u4ee4\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7tmux \u5728\u4e00\u4e2a\u7ec8\u7aef\u5185\u7ba1\u7406\u591a\u4e2a\u5206\u79bb\u7684\u4f1a\u8bdd\uff0c\u7a97\u53e3\u53ca\u9762\u677f\uff0c\u5bf9\u4e8e\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u547d\u4ee4\u884c\uff0c\u6216\u591a\u4e2a\u4efb\u52a1\u65f6\u975e\u5e38\u65b9\u4fbf\u3002 \u521b\u5efa\u4f1a\u8bdd \u6bd4\u5982\u4f60\u60f3\u540c\u65f6\u76d1\u63a7 CPU\u3001\u5185\u5b58\u3001\u663e\u5361\u4f7f\u7528\u60c5\u51b5\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u5728\u4f7f\u7528 iTerm2 \u7684\u60c5\u51b5\u4e0b\uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u5f00\u542f\u4e00\u4e2a tmux \u4f1a\u8bdd(session)\uff1a tmux -CC new -s monitor \u5176\u4e2d\u7684 monitor \u662f\u8fd9\u4e2a\u4f1a\u8bdd\u7684\u540d\u5b57\uff0c\u4f60\u53ef\u4ee5\u4fee\u6539\u4e3a\u81ea\u5df1\u559c\u6b22\u7684\u540d\u5b57\u3002 \u4fee\u6539\u5e03\u5c40 \u5728\u5f39\u51fa\u7684\u7a97\u53e3(window)\u4e2d\uff0c\u4f60\u53ef\u4ee5\uff1a \u4f7f\u7528 \u2318+D Command + D \u6a2a\u5411\u5206\u5272\u8fd9\u4e2a\u7a97\u53e3 \u4f7f\u7528 \u2318+\u21e7+D Command + Shift + D \u7eb5\u5411\u5206\u5272\u8fd9\u4e2a\u7a97\u53e3 \u4f7f\u7528 \u2318+N Command + N \u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u7a97\u53e3 \u5f53\u4f60\u8c03\u6574\u597d\u5e03\u5c40\u4ee5\u540e\uff0c\u53ef\u4ee5\u5728\u6bcf\u4e2a\u7a97\u683c(panel)\u91cc\u8fd0\u884c\u4f60\u60f3\u8fd0\u884c\u7684\u547d\u4ee4\u3002 \u7a97\u53e3\u5927\u5c0f\u53ef\u4ee5\u4f7f\u7528\u9f20\u6807\u8fdb\u884c\u8c03\u6574\uff0c\u7a97\u683c\u5927\u5c0f\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9f20\u6807\u62d6\u52a8\u4fee\u6539\u3002 \u4fee\u6539\u597d\u4ee5\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u7c7b\u4f3c\u4e0b\u56fe\u7684\u6548\u679c\uff1a \u8131\u79bb\u4f1a\u8bdd \u5982\u679c\u4f60\u60f3\u8ba9 python \u811a\u672c\u5728\u540e\u53f0\u8fd0\u884c\uff0c\u53ea\u9700\u8981\u5728\u521a\u624d\u521b\u5efa\u4f1a\u8bdd\u7684\u5730\u65b9\u6309\u4e00\u4e0b esc \u952e\uff0c\u5c31\u53ef\u4ee5\u8131\u79bb\u8fd9\u4e2a\u4f1a\u8bdd\u3002 \u279c ~ tmux -CC new -s monitor ** tmux mode started ** Command Menu ---------------------------- esc Detach cleanly. X Force-quit tmux mode. L Toggle logging. C Run tmux command. \u4f60\u4e5f\u53ef\u4ee5\u76f4\u63a5\u5173\u95ed\u5f00\u542f\u4f1a\u8bdd\u7684\u7ec8\u7aef\u7684\u7a97\u53e3\uff0c\u6548\u679c\u4e00\u6837\u3002 \u6062\u590d\u4f1a\u8bdd \u6062\u590d\u4f1a\u8bdd\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\uff1a tmux -CC attach -t monitor \u9000\u51fa\u4f1a\u8bdd \u5982\u679c\u4f60\u60f3\u5b8c\u5168\u9000\u51fa\u6240\u6709\u7684\u7ec8\u7aef\uff0c\u53ea\u9700\u8981\u5728\u6bcf\u4e2a\u7a97\u683c\u91cc \u2318+W Command + W \u5373\u53ef\uff0c\u5173\u95ed\u6700\u540e\u4e00\u4e2a\u7a97\u53e3\u4ee5\u540e\uff0c\u8fd9\u4e2a\u4f1a\u8bdd\u5c31\u7ed3\u675f\u4e86\u3002 screen screen \u548c tmux \u4e00\u6837\u90fd\u662f\u5728\u540e\u53f0\u8fd0\u884c\u547d\u4ee4\u7684\u5de5\u5177\u3002 \u65b0\u5efa\u7a97\u53e3 screen -S jupyter \u5176\u4e2d -S \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002 \u6062\u590d\u7a97\u53e3 screen -r jupyter \u5176\u4e2d -r \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002 \u9000\u51fa\u7a97\u53e3 \u4f60\u53ef\u4ee5\u5728\u7a97\u53e3\u4e2d\u4f7f\u7528 exit \u547d\u4ee4\u9000\u51fa\u7a97\u53e3\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a screen -X -S jupyter quit \u5176\u4e2d -S \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002 \u5728 screen \u91cc\u652f\u6301\u6eda\u8f6e \u65b0\u5efa\u4e00\u4e2a ~/.screenrc \u6587\u4ef6\uff0c\u5728\u91cc\u9762\u6dfb\u52a0\u4e00\u884c termcapinfo xterm* ti@:te@ \u5e76\u4fdd\u5b58\uff0c\u91cd\u65b0\u8fde\u63a5 screen \u5c31\u53ef\u4ee5\u4f7f\u7528\u6eda\u8f6e\u4e86\u3002 \u8fdb\u5165\u62f7\u8d1d\u6a21\u5f0f \u8f93\u5165\u5feb\u6377\u952e Ctrl + a + [ \u8fdb\u5165\u62f7\u8d1d\u6a21\u5f0f\uff0c\u7136\u540e\u4f60\u5c31\u53ef\u4ee5\u4f7f\u7528\u65b9\u5411\u952e\u3001\u7ffb\u9875\u952e\u8fdb\u884c\u7ffb\u9875\u3002 \u4e0b\u9762\u662f\u62f7\u8d1d\u6a21\u5f0f\u4e0b\u7684\u5e38\u7528\u5feb\u6377\u952e\uff1a h - Move the cursor left by one character j - Move the cursor down by one line k - Move the cursor up by one line l - Move the cursor right by one character 0 - Move to the beginning of the current line $ - Move to the end of the current line. G - Moves to the specified line (defaults to the end of the buffer). C-u - Scrolls a half page up. C-b - Scrolls a full page up. C-d - Scrolls a half page down. C-f - Scrolls the full page down. \u5982\u679c\u4f60\u8bb0\u4e0d\u5f97\u8fd9\u4e48\u591a\u5feb\u6377\u952e\uff0c\u63a8\u8350 iTerm2 + tmux \u7684\u7ec4\u5408\u3002","title":"Ubuntu \u73af\u5883"},{"location":"ubuntu-environment/#ubuntu","text":"","title":"Ubuntu \u73af\u5883"},{"location":"ubuntu-environment/#cuda","text":"\u6700\u65b0\u7248\uff1a https://developer.nvidia.com/cuda-downloads CUDA 11.3\uff1a https://developer.nvidia.com/cuda-11-3-1-download-archive CUDA 10.2\uff1a https://developer.nvidia.com/cuda-10.2-download-archive CUDA 10.1\uff1a https://developer.nvidia.com/cuda-10.1-download-archive-update2 CUDA 10.0\uff1a https://developer.nvidia.com/cuda-10.0-download-archive \u65e7\u7248\u5217\u8868\uff1a https://developer.nvidia.com/cuda-toolkit-archive CUDA \u662f\u82f1\u4f1f\u8fbe\u663e\u5361\u8fdb\u884c\u5404\u79cd\u9ad8\u6027\u80fd\u8fd0\u7b97\u5fc5\u5907\u7684\u5e93\uff0c\u4e0d\u540c\u8f6f\u4ef6\u5305\u4f9d\u8d56\u7684 CUDA \u7248\u672c\u53ef\u80fd\u4e0d\u540c\uff0c\u4f60\u9700\u8981\u6839\u636e\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u9009\u62e9\u5408\u9002\u7684 CUDA \u548c cuDNN \u7248\u672c\u3002 \u7248\u672c Windows 10 Linux CUDA 11.3 cuda_11.3.1_465.89_win10.exe cuda_11.3.1_465.19.01_linux.run CUDA 10.2 cuda_10.2.89_441.22_win10.exe cuda_10.2.89_440.33.01_linux.run CUDA 10.1 cuda_10.1.243_426.00_win10.exe cuda_10.1.243_418.87.00_linux.run CUDA 10.0 cuda_10.0.130_411.31_win10.exe cuda_10.0.130_410.48_linux.run \u4ee5\u4e0b\u7248\u672c\u8f83\u4f4e\uff0c\u63a8\u8350\u4f7f\u7528\u4e0a\u9762\u7684\u7248\u672c\u3002 CUDA 9.2 cuda_9.2.148_win10.exe cuda_9.2.148_396.37_linux.run CUDA 9.1 cuda_9.1.85_win10.exe cuda_9.1.85_387.26_linux.run CUDA 9.0 cuda_9.0.176_win10.exe cuda_9.0.176_384.81_linux.run CUDA 8.0 GA2 cuda_8.0.61_win10.exe cuda_8.0.61_375.26_linux.run CUDA 8.0 GA1 cuda_8.0.44_win10.exe cuda_8.0.44_linux.run CUDA 7.5 cuda_7.5.18_win10.exe cuda_7.5.18_linux.run CUDA 7.0 cuda_7.0.28_windows.exe cuda_7.0.28_linux.run CUDA 6.5 cuda_6.5.14_windows_general_64.exe cuda_6.5.14_linux_64.run","title":"CUDA"},{"location":"ubuntu-environment/#cudnn","text":"cuDNN \u4e0b\u8f7d\u9700\u8981\u6ce8\u518c\uff0c\u5730\u5740\u5982\u4e0b\uff1a \u6700\u65b0\u7248\uff1a https://developer.nvidia.com/cudnn \u65e7\u7248\uff1a https://developer.nvidia.com/rdp/cudnn-archive cuDNN \u662f\u82f1\u4f1f\u8fbe\u63a8\u51fa\u7684\u4e13\u95e8\u7528\u4e8e\u6df1\u5ea6\u5b66\u4e60\u52a0\u901f\u8ba1\u7b97\u7684\u5e93\uff0c\u4e00\u822c\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u4f1a\u4f7f\u7528 cuDNN\u3002 \u4f60\u9700\u8981\u6839\u636e\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u9009\u62e9\u5408\u9002\u7684 CUDA \u548c cuDNN \u7248\u672c\u3002 \u4e0b\u8868\u662f\u5e38\u89c1\u7248\u672c\u7684 cuDNN Linux \u4e0b\u8f7d\u94fe\u63a5\uff1a cuDNN CUDA9.0 CUDA10.0 CUDA10.2 CUDA11.2 CUDA11.3 8.2.1 - - cudnn-10.2-linux-x64-v8.2.1.32.tgz (959.98MB) - cudnn-11.3-linux-x64-v8.2.1.32.tgz (1.75GB) 8.1.0 - - cudnn-10.2-linux-x64-v8.1.0.77.tgz (720.54MB) cudnn-11.2-linux-x64-v8.1.0.77.tgz (1.23GB) - 7.4.1 cudnn-9.0-linux-x64-v7.4.1.5.tgz (347.17MB) cudnn-10.0-linux-x64-v7.4.1.5.tgz (403.12MB) - - - 7.2.1 cudnn-9.0-linux-x64-v7.2.1.38.tgz (331.19MB) - - - - 7.1.4 cudnn-9.0-linux-x64-v7.1.tgz (390.26MB) - - - - \u4e0b\u8868\u662f\u5e38\u89c1\u7248\u672c\u7684 cuDNN Windows \u4e0b\u8f7d\u94fe\u63a5\uff1a cuDNN CUDA9.0 CUDA10.0 CUDA10.2 CUDA11.2 CUDA11.3 8.2.1 - - cudnn-10.2-windows10-x64-v8.2.1.32.zip (392.82MB) - - 8.1.0 - - cudnn-10.2-windows10-x64-v8.1.0.77.zip (358.77MB) - - 7.4.1 cudnn-9.0-windows10-x64-v7.4.1.5.zip (179.09MB) cudnn-10.0-windows10-x64-v7.4.1.5.zip (208.93MB) - - - 7.2.1 cudnn-9.0-windows10-x64-v7.2.1.38.zip (171.64MB) - - - - 7.1.4 cudnn-9.0-windows10-x64-v7.1.zip (201.39MB) - - - -","title":"cuDNN"},{"location":"ubuntu-environment/#tensorrt","text":"TensorRT \u662f\u82f1\u4f1f\u8fbe\u63a8\u51fa\u7684\u63a8\u65ad\u5e93\uff08Inference\uff09\uff0c\u901a\u5e38\u7528\u4e8e\u6a21\u578b\u90e8\u7f72\u3002 \u4f7f\u7528 TensorRT \u53ef\u4ee5\u8fdb\u884c\u534a\u7cbe\u5ea6\u63a8\u65ad\uff0c\u751a\u81f3\u5bf9\u6a21\u578b\u8fdb\u884c int8 \u91cf\u5316\uff0c\u4ece\u800c\u5f97\u5230\u6570\u500d\u7684\u6027\u80fd\u63d0\u5347\uff0c\u5e76\u4e14\u5c3d\u53ef\u80fd\u4fdd\u8bc1\u7cbe\u5ea6\u3002\u7531\u4e8e\u6b64\u9879\u76ee\u8fd8\u5728\u5f00\u53d1\u9636\u6bb5\uff0c\u4e0d\u540c\u7684\u7248\u672c\u53ef\u80fd\u4e0d\u901a\u7528\uff0c\u8bf7\u53c2\u8003\u4f60\u6240\u4f7f\u7528\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u6587\u6863\uff0c\u627e\u5230\u4f60\u6240\u9700\u8981\u5b89\u88c5\u7684 TensorRT \u7248\u672c\u3002","title":"TensorRT"},{"location":"ubuntu-environment/#tensorflow","text":"\u5b89\u88c5\u6559\u7a0b\uff1a https://www.tensorflow.org/install/gpu \u6700\u65b0\u7248\u7684 TensorFlow 1.14.0 \u4f9d\u8d56 CUDA 10.0\uff0c\u5e76\u4e14 cuDNN \u9700\u8981 7.4.1 \u6216\u66f4\u9ad8\u7684\u7248\u672c\uff0cNVIDIA \u9a71\u52a8\u9700\u8981 410.x \u6216\u66f4\u9ad8\u7248\u672c\u3002","title":"TensorFlow"},{"location":"ubuntu-environment/#_1","text":"TensorFlow CUDA cuDNN NVIDIA Driver NCCL TensorRT 1.14 10.0 7.4.1 410 2.2 5.0 1.13 10.0 7.4.1 410 2.2 5.0 1.12 9.0 7.2 384 2.2 4.0 1.11 9.0 7.2 384 2.2 4.0 1.10 9.0 7.1 384 2.2 4.0 1.9 9.0 7.0 3.0 1.8 9.0 7.0 3.0 1.7 9.0 7.0 3.0 1.6 9.0 7.0 1.5 9.0 7.0 1.4 8.0 6.0 1.3 8.0 6.0 1.2 8.0 5.1 1.1 8.0 5.1 1.0 8.0 5.1 \u63d0\u793a\uff1a NVIDIA Driver \u4e3a\u7a7a\uff0c\u5b98\u65b9\u6587\u6863\u8bf4\u7684\u662f\u53ea\u8981\u5b89\u88c5\u6ee1\u8db3 CUDA \u7248\u672c\u7684\u9a71\u52a8\u5373\u53ef NCCL \u548c TensorRT \u4e3a\u7a7a\uff0c\u8868\u793a\u4e0d\u9700\u8981\u5b89\u88c5","title":"\u5386\u53f2\u7248\u672c\u4f9d\u8d56\u73af\u5883"},{"location":"ubuntu-environment/#pytorch","text":"PyTorch \u81ea\u5e26 CUDA \u548c cuDNN\uff0c\u53ea\u9700\u8981\u5b89\u88c5 NVIDIA \u9a71\u52a8\u5373\u53ef\u8fd0\u884c\u3002 \u76ee\u524d PyPI \u5b89\u88c5\u7684 PyTorch \u4f7f\u7528\u7684\u662f CUDA9.0\uff0c\u5982\u679c\u4f60\u9700\u8981\u5176\u4ed6\u7248\u672c\uff0c\u8bf7\u4f7f\u7528\u5b98\u7f51\u4e0a\u7684\u9009\u62e9\u5668\u627e\u5230\u4f60\u9700\u8981\u7684\u7248\u672c\uff0c\u6bd4\u5982 Python 3.7 \u5b89\u88c5 CUDA10 \u7684 PyTorch \u9700\u8981\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a pip3 install https://download.pytorch.org/whl/cu100/torch-1.1.0-cp37-cp37m-linux_x86_64.whl pip3 install https://download.pytorch.org/whl/cu100/torchvision-0.3.0-cp37-cp37m-linux_x86_64.whl","title":"PyTorch"},{"location":"ubuntu-environment/#_2","text":"sudo apt install -y git curl htop nload tmux screen aria2 graphviz aptitude tree iotop \u5e38\u89c1\u7684 git\u3001htop\u3001nload \u7b49\u547d\u4ee4\u5728 macOS \u73af\u5883 \u91cc\u5df2\u7ecf\u4ecb\u7ecd\u8fc7\u4e86\u3002\u5176\u5b9e\u5927\u90e8\u5206\u547d\u4ee4\u5728\u6ca1\u6709\u5b89\u88c5\u7684\u65f6\u5019\uff0c\u5982\u679c\u4f60\u4f7f\u7528\u5b83\u4eec\uff0c\u4f1a\u81ea\u52a8\u63d0\u793a\u9700\u8981\u5b89\u88c5\uff0c\u6240\u4ee5\u4e0d\u7528\u62c5\u5fc3\u6ca1\u6709\u5b89\u88c5\u5168\uff1a ypw@ypw-ubuntu:~$ screen Command 'screen' not found, but can be installed with: sudo apt install screen","title":"\u5fc5\u5907\u547d\u4ee4"},{"location":"ubuntu-environment/#curl","text":"curl \u662f\u4e00\u4e2a\u591a\u529f\u80fd\u7684\u7f51\u7edc\u64cd\u4f5c\u547d\u4ee4\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u5b83\u6765\u53d1\u9001 GET\u3001POST \u8bf7\u6c42\u3002 \u5728\u5f00\u53d1\u670d\u52a1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4f1a\u7ecf\u5e38\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\u6765\u6d4b\u8bd5\u670d\u52a1\u662f\u5426\u80fd\u8fd4\u56de\u9884\u671f\u7684\u7ed3\u679c\u3002 GET\uff1a curl https://dl.ypw.io POST\uff1a curl -d \"param1=value1¶m2=value2\" -X POST http://localhost:3000/data POST json\uff1a curl -d '{\"key1\":\"value1\", \"key2\":\"value2\"}' -H \"Content-Type: application/json\" -X POST http://localhost:3000/data","title":"curl"},{"location":"ubuntu-environment/#tmux","text":"tmux \u6700\u5927\u7684\u597d\u5904\u662f\u53ef\u4ee5\u8ba9\u4f60\u7684\u547d\u4ee4\u5728\u540e\u53f0\u8fd0\u884c\uff0c\u4e0d\u4f1a\u56e0\u4e3a\u7ec8\u7aef\u5173\u95ed\u800c\u9000\u51fa\u3002\u6bd4\u5982\u5728\u540e\u53f0\u8fd0\u884c jupyter\u3001python \u6570\u636e\u9884\u5904\u7406\u811a\u672c\u548c\u8bad\u7ec3\u811a\u672c\u7b49\u3002 tmux \u662f\u4e00\u4e2a\u4f18\u79c0\u7684\u7ec8\u7aef\u590d\u7528\u5668\u547d\u4ee4\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7tmux \u5728\u4e00\u4e2a\u7ec8\u7aef\u5185\u7ba1\u7406\u591a\u4e2a\u5206\u79bb\u7684\u4f1a\u8bdd\uff0c\u7a97\u53e3\u53ca\u9762\u677f\uff0c\u5bf9\u4e8e\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u547d\u4ee4\u884c\uff0c\u6216\u591a\u4e2a\u4efb\u52a1\u65f6\u975e\u5e38\u65b9\u4fbf\u3002","title":"tmux"},{"location":"ubuntu-environment/#_3","text":"\u6bd4\u5982\u4f60\u60f3\u540c\u65f6\u76d1\u63a7 CPU\u3001\u5185\u5b58\u3001\u663e\u5361\u4f7f\u7528\u60c5\u51b5\uff0c\u90a3\u4e48\u4f60\u53ef\u4ee5\u5728\u4f7f\u7528 iTerm2 \u7684\u60c5\u51b5\u4e0b\uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u5f00\u542f\u4e00\u4e2a tmux \u4f1a\u8bdd(session)\uff1a tmux -CC new -s monitor \u5176\u4e2d\u7684 monitor \u662f\u8fd9\u4e2a\u4f1a\u8bdd\u7684\u540d\u5b57\uff0c\u4f60\u53ef\u4ee5\u4fee\u6539\u4e3a\u81ea\u5df1\u559c\u6b22\u7684\u540d\u5b57\u3002","title":"\u521b\u5efa\u4f1a\u8bdd"},{"location":"ubuntu-environment/#_4","text":"\u5728\u5f39\u51fa\u7684\u7a97\u53e3(window)\u4e2d\uff0c\u4f60\u53ef\u4ee5\uff1a \u4f7f\u7528 \u2318+D Command + D \u6a2a\u5411\u5206\u5272\u8fd9\u4e2a\u7a97\u53e3 \u4f7f\u7528 \u2318+\u21e7+D Command + Shift + D \u7eb5\u5411\u5206\u5272\u8fd9\u4e2a\u7a97\u53e3 \u4f7f\u7528 \u2318+N Command + N \u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u7a97\u53e3 \u5f53\u4f60\u8c03\u6574\u597d\u5e03\u5c40\u4ee5\u540e\uff0c\u53ef\u4ee5\u5728\u6bcf\u4e2a\u7a97\u683c(panel)\u91cc\u8fd0\u884c\u4f60\u60f3\u8fd0\u884c\u7684\u547d\u4ee4\u3002 \u7a97\u53e3\u5927\u5c0f\u53ef\u4ee5\u4f7f\u7528\u9f20\u6807\u8fdb\u884c\u8c03\u6574\uff0c\u7a97\u683c\u5927\u5c0f\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9f20\u6807\u62d6\u52a8\u4fee\u6539\u3002 \u4fee\u6539\u597d\u4ee5\u540e\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u7c7b\u4f3c\u4e0b\u56fe\u7684\u6548\u679c\uff1a","title":"\u4fee\u6539\u5e03\u5c40"},{"location":"ubuntu-environment/#_5","text":"\u5982\u679c\u4f60\u60f3\u8ba9 python \u811a\u672c\u5728\u540e\u53f0\u8fd0\u884c\uff0c\u53ea\u9700\u8981\u5728\u521a\u624d\u521b\u5efa\u4f1a\u8bdd\u7684\u5730\u65b9\u6309\u4e00\u4e0b esc \u952e\uff0c\u5c31\u53ef\u4ee5\u8131\u79bb\u8fd9\u4e2a\u4f1a\u8bdd\u3002 \u279c ~ tmux -CC new -s monitor ** tmux mode started ** Command Menu ---------------------------- esc Detach cleanly. X Force-quit tmux mode. L Toggle logging. C Run tmux command. \u4f60\u4e5f\u53ef\u4ee5\u76f4\u63a5\u5173\u95ed\u5f00\u542f\u4f1a\u8bdd\u7684\u7ec8\u7aef\u7684\u7a97\u53e3\uff0c\u6548\u679c\u4e00\u6837\u3002","title":"\u8131\u79bb\u4f1a\u8bdd"},{"location":"ubuntu-environment/#_6","text":"\u6062\u590d\u4f1a\u8bdd\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u547d\u4ee4\uff1a tmux -CC attach -t monitor","title":"\u6062\u590d\u4f1a\u8bdd"},{"location":"ubuntu-environment/#_7","text":"\u5982\u679c\u4f60\u60f3\u5b8c\u5168\u9000\u51fa\u6240\u6709\u7684\u7ec8\u7aef\uff0c\u53ea\u9700\u8981\u5728\u6bcf\u4e2a\u7a97\u683c\u91cc \u2318+W Command + W \u5373\u53ef\uff0c\u5173\u95ed\u6700\u540e\u4e00\u4e2a\u7a97\u53e3\u4ee5\u540e\uff0c\u8fd9\u4e2a\u4f1a\u8bdd\u5c31\u7ed3\u675f\u4e86\u3002","title":"\u9000\u51fa\u4f1a\u8bdd"},{"location":"ubuntu-environment/#screen","text":"screen \u548c tmux \u4e00\u6837\u90fd\u662f\u5728\u540e\u53f0\u8fd0\u884c\u547d\u4ee4\u7684\u5de5\u5177\u3002","title":"screen"},{"location":"ubuntu-environment/#_8","text":"screen -S jupyter \u5176\u4e2d -S \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002","title":"\u65b0\u5efa\u7a97\u53e3"},{"location":"ubuntu-environment/#_9","text":"screen -r jupyter \u5176\u4e2d -r \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002","title":"\u6062\u590d\u7a97\u53e3"},{"location":"ubuntu-environment/#_10","text":"\u4f60\u53ef\u4ee5\u5728\u7a97\u53e3\u4e2d\u4f7f\u7528 exit \u547d\u4ee4\u9000\u51fa\u7a97\u53e3\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\uff1a screen -X -S jupyter quit \u5176\u4e2d -S \u540e\u9762\u8ddf\u7684\u662f screen \u7684\u540d\u5b57\u3002","title":"\u9000\u51fa\u7a97\u53e3"},{"location":"ubuntu-environment/#screen_1","text":"\u65b0\u5efa\u4e00\u4e2a ~/.screenrc \u6587\u4ef6\uff0c\u5728\u91cc\u9762\u6dfb\u52a0\u4e00\u884c termcapinfo xterm* ti@:te@ \u5e76\u4fdd\u5b58\uff0c\u91cd\u65b0\u8fde\u63a5 screen \u5c31\u53ef\u4ee5\u4f7f\u7528\u6eda\u8f6e\u4e86\u3002","title":"\u5728 screen \u91cc\u652f\u6301\u6eda\u8f6e"},{"location":"ubuntu-environment/#_11","text":"\u8f93\u5165\u5feb\u6377\u952e Ctrl + a + [ \u8fdb\u5165\u62f7\u8d1d\u6a21\u5f0f\uff0c\u7136\u540e\u4f60\u5c31\u53ef\u4ee5\u4f7f\u7528\u65b9\u5411\u952e\u3001\u7ffb\u9875\u952e\u8fdb\u884c\u7ffb\u9875\u3002 \u4e0b\u9762\u662f\u62f7\u8d1d\u6a21\u5f0f\u4e0b\u7684\u5e38\u7528\u5feb\u6377\u952e\uff1a h - Move the cursor left by one character j - Move the cursor down by one line k - Move the cursor up by one line l - Move the cursor right by one character 0 - Move to the beginning of the current line $ - Move to the end of the current line. G - Moves to the specified line (defaults to the end of the buffer). C-u - Scrolls a half page up. C-b - Scrolls a full page up. C-d - Scrolls a half page down. C-f - Scrolls the full page down. \u5982\u679c\u4f60\u8bb0\u4e0d\u5f97\u8fd9\u4e48\u591a\u5feb\u6377\u952e\uff0c\u63a8\u8350 iTerm2 + tmux \u7684\u7ec4\u5408\u3002","title":"\u8fdb\u5165\u62f7\u8d1d\u6a21\u5f0f"},{"location":"ubuntu-install-guide/","text":"Ubuntu \u88c5\u673a\u6b65\u9aa4 \u5b89\u88c5 Ubuntu \u914d\u7f6e ssh \u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90\uff08\u63a8\u8350\uff09 \u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4\uff08\u63a8\u8350\uff09 \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08\u5206\u4e3a apt \u548c run \u4e24\u79cd\u5b89\u88c5\u65b9\u5f0f\uff09 \u5b89\u88c5 Anaconda \u548c Python \u5e93 \u811a\u672c\u5f0f\u88c5\u673a Ubuntu 22.04 \u4ee5\u524d\uff1a # \u6dfb\u52a0 sudo \u514d\u5bc6\u7801 if [ [ $ ( sudo grep -L $USER / etc / sudoers ) ] ]; then echo \"Add $USER to sudoers\" echo \"$USER ALL=(ALL) NOPASSWD:ALL\" | sudo tee -a / etc / sudoers ; fi Ubuntu 22.04 \u53ca\u4ee5\u540e\uff1a FILE = \" /etc/sudoers.d/$USER \" if [ ! - f \" $FILE \" ] ; then echo \" Create $FILE and add sudo permission \" echo \" $USER ALL=(ALL) NOPASSWD:ALL \" | sudo tee \" $FILE \" fi # \u5347\u7ea7\u7cfb\u7edf sudo apt update sudo apt upgrade -y # \u5b89\u88c5\u5e38\u7528\u547d\u4ee4\u548c oh-my-zsh sudo apt install - y openssh - server git curl zsh net - tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop cifs - utils landscape - common p7zip - full sh - c \"$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)\" # \u5b89\u88c5 Python \u73af\u5883 wget https://mirrors.bfsu.edu.cn/anaconda/miniconda/Miniconda3-py310_23.3.1-0-Linux-x86_64.sh bash Miniconda3-py310_23.3.1-0-Linux-x86_64.sh -b ~/miniconda3/bin/conda init bash ~/miniconda3/bin/conda init zsh # reboot your terminal ~/ miniconda3 / bin / conda activate # pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ # pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip config set global . index - url https : // mirrors . bfsu . edu . cn / pypi / web / simple pip install torch == 2.1 . 1 + cu118 torchvision == 0.16 . 1 + cu118 -- index - url https : // download . pytorch . org / whl / cu118 pip install jupyter jupyter_contrib_nbextensions numpy pandas flask scikit - image scikit - learn matplotlib opencv - python pillow tqdm openpyxl ninja xtcocotools json_tricks munkres shapely ftfy pytest regex pyyaml yapf cython build twine memory_profiler pip install openmim mim install mmpretrain mmdet mmpose mmsegmentation \u5b89\u88c5 CUDA\uff1a Ubuntu 18.04\uff1a # \u5b89\u88c5 CUDA 11.8\uff0cubuntu18.04 wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu1804 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda - 11 - 8 Ubuntu 20.04\uff1a wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu2004 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda11 - 8 Ubuntu 22.04 \u53c2\u8003\u94fe\u63a5 \uff1a wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu2204 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda - 11 - 8 \u5b89\u88c5\u6307\u5b9a\u7248\u672c\u7684 cudnn\uff1a sudo apt install libcudnn8 = 8 .7.0.84-1+cuda11.8 libcudnn8-dev = 8 .7.0.84-1+cuda11.8 \u6dfb\u52a0 CUDA \u73af\u5883\u53d8\u91cf\uff1a # CUDA \u73af\u5883\u53d8\u91cf if [[ $ ( grep - L \"cuda\" ~/. bashrc ) ]]; then echo \"Add CUDA environment to ~/.bashrc\" echo \"export PATH=/usr/local/cuda/bin:\\$PATH\" | tee - a ~/. bashrc ; echo \"export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\\$LD_LIBRARY_PATH\" | tee - a ~/. bashrc ; fi if [[ $ ( grep - L \"cuda\" ~/. zshrc ) ]]; then echo \"Add CUDA environment to ~/.zshrc\" echo \"export PATH=/usr/local/cuda/bin:\\$PATH\" | tee - a ~/. zshrc ; echo \"export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\\$LD_LIBRARY_PATH\" | tee - a ~/. zshrc ; fi \u5b89\u88c5 mmdet\uff1a mim install mmdet \u5b89\u88c5 Ubuntu \u4ee5\u4e0b\u662f Ubuntu \u5b98\u65b9\u7f51\u7ad9\u4e0a\u7684\u6559\u7a0b\uff1a \u5728 Windows \u4e0a\u5236\u4f5c Ubuntu \u7cfb\u7edf\u76d8 \u5728 macOS \u4e0a\u5236\u4f5c Ubuntu \u7cfb\u7edf\u76d8 \u5b89\u88c5 Ubuntu \u76ee\u524d\u6211\u5b89\u88c5\u7684\u7248\u672c\u662f Ubuntu 18.04 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528\u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf\uff1a https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/18.04.4/ubuntu-18.04.4-desktop-amd64.iso \u5982\u679c\u4e0a\u9762\u7684\u94fe\u63a5\u5931\u6548\u4e86\uff0c\u8bf4\u660e ubuntu \u51fa\u65b0\u7248\u4e86\uff0c\u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u67e5\u627e\u65b0\u7248\uff1a https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/ \u3002 \u914d\u7f6e ssh \u5b89\u88c5 openssh-server \u88c5\u597d Ubuntu \u4ee5\u540e\uff0c\u4e3a\u4e86\u80fd\u591f\u65b9\u4fbf\u5730\u5728\u5176\u4ed6\u7ec8\u7aef\u4e0a\u8fdc\u7a0b\u8fde\u63a5\uff0c\u5b89\u88c5\u5404\u79cd\u8f6f\u4ef6\uff0c\u6211\u4e00\u822c\u4f1a\u5148\u88c5 openssh-server\u3002 sudo apt update sudo apt install openssh-server \u88c5\u597d\u4e86\u4ee5\u540e\uff0c\u5c31\u53ef\u4ee5\u5728\u7ec8\u7aef\u91cc\u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\u8fde\u63a5\u670d\u52a1\u5668\u3002 ssh 192 .168.8.65 \u4f7f\u7528\u5230\u7684\u547d\u4ee4\uff1a apt \u3001 ssh \u4f7f\u7528 ssh-keygen \u751f\u6210\u4e00\u4e2a ssh key \u76ee\u524d\u4f7f\u7528\u5bc6\u7801\u4e0a\u4e0d\u5982\u4f7f\u7528 key \u5b89\u5168\u7684\uff0c\u56e0\u4e3a key \u7684\u957f\u5ea6\u901a\u5e38\u662f 2048 \u6216 4096 \u4f4d\uff0c\u8fdc\u8d85\u666e\u901a\u7684\u5bc6\u7801\u3002\u8fd9\u91cc\u5efa\u8bae\u6309\u7167 GitHub \u5b98\u65b9\u7f51\u7ad9\u4e0a\u7684\u6559\u7a0b \u751f\u6210\u65b0 SSH \u5bc6\u94a5\u5e76\u6dfb\u52a0\u5230 ssh-agent \uff0c\u8fd9\u6837\u4e0d\u4ec5\u53ef\u4ee5\u7528\u4e8e\u767b\u5f55 Linux \u673a\u5668\uff0c\u4e5f\u53ef\u4ee5\u7528\u4e8e git\u3002 \u4f7f\u7528 ssh-keygen \u751f\u6210\u4e86\u5bc6\u94a5\u4ee5\u540e\uff0c\u4f60\u4f1a\u5f97\u5230\u4e24\u4e2a\u6587\u4ef6\uff1a ~/.ssh/id_rsa ~/.ssh/id_rsa.pub \u5176\u4e2d id_rsa \u662f\u79c1\u94a5\uff0c id_rsa.pub \u662f\u516c\u94a5\u3002\u4e0d\u8981\u628a\u79c1\u94a5\u53d1\u7ed9\u4efb\u4f55\u4eba\u3002 \u200b\u516c\u94a5\u901a\u5e38\u4e0a\u8fd9\u6837\u7684\u6587\u672c\uff1a ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcfQD4nnaQrgC003C0ReAYqrm6XKEchuM6DwkNtHzRs2YhLolH6fEohWAp0mlW9yzQl258lA+FdoH51ONmvGUx/2Y953A6ujHrt7dOIpOkYW5HT6Rmvlwk+3uRmVNQqZTJeRWdblcSHmYY1fi1miawONZiVoLW14xhyH5bOwgwY/GB2yTaffDby451RLT5kQ7LHqiDJtWiRQekR5tKDKZ7mBhKZIKYLOoqAayCHw2scJYsgtw2tPt0/y7BlxO+RuDwuD2WOnthe1ewbwAbbTN17HiLvBd/MIWtVDoGGq6jdNDjNDNbTs8H2VohTc2mNtOOlycN6yzf3ZKZTN6/hNtl ypw@yangpeiendeiMac \u5728 Ubuntu \u670d\u52a1\u5668\u4e0a\u6dfb\u52a0\u521a\u624d\u751f\u6210\u7684 ssh key \u9996\u5148\u4f7f\u7528\u5bc6\u7801\u767b\u5f55\u521a\u624d\u7684\u673a\u5668\uff1a ssh 192 .168.8.65 \u7136\u540e\u521b\u5efa ~/.ssh \u76ee\u5f55\uff0c\u5e76\u4e14\u521b\u5efa ~/.ssh/authorized_keys \u6587\u4ef6\uff0c\u914d\u7f6e\u597d\u76f8\u5e94\u7684\u6743\u9650\uff1a mkdir -p ~/.ssh touch ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys nano ~/.ssh/authorized_keys # \u6dfb\u52a0\u4f60\u7684\u516c\u94a5\uff0c\u5982 ssh-rsa AAAA... \u628a\u521a\u624d\u751f\u6210\u7684\u516c\u94a5 id_rsa.pub \u6dfb\u52a0\u5230 ~/.ssh/authorized_keys \u91cc\uff0c\u5982\u679c\u6587\u4ef6\u5df2\u7ecf\u6709\u5185\u5bb9\uff0c\u5c31\u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c\u3002\u8fd9\u6837\u4ee5\u540e \u6bcf\u6b21\u4f7f\u7528 ssh \u767b\u5f55\u673a\u5668\u90fd\u4e0d\u9700\u8981\u518d\u8f93\u5165\u5bc6\u7801\u4e86 \u3002 \u4f7f\u7528\u5230\u7684\u547d\u4ee4\uff1a mkdir \u3001 touch \u3001 chmod \u3001 nano \u7981\u6b62\u5bc6\u7801\u767b\u5f55 \u7531\u4e8e\u5bc6\u7801\u767b\u5f55\u5b58\u5728\u4e0d\u5b89\u5168\u56e0\u7d20\uff0c\u6bd4\u5982\u66b4\u9732\u5728\u516c\u7f51\u7684 IP \u4f1a\u88ab\u626b\u63cf\uff0c\u800c key \u662f\u76f8\u5bf9\u5b89\u5168\u7684\uff0c\u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u7981\u6b62\u4e0d\u5b89\u5168\u7684\u5bc6\u7801\u767b\u5f55\uff1a sudo nano /etc/ssh/sshd_config PasswordAuthentication no # \u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c \u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90 \u914d\u7f6e sudo \u514d\u5bc6\u7801 Ubuntu 22.04 \u4ee5\u524d\uff1a \u7531\u4e8e\u5b89\u88c5\u9a71\u52a8\u7b49\u64cd\u4f5c\u9700\u8981 sudo \u6743\u9650\uff0c\u4e3a\u4e86\u907f\u514d\u9891\u7e41\u8f93\u5165\u5bc6\u7801\uff0c\u53ef\u4ee5\u914d\u7f6e sudo \u514d\u5bc6\u7801\uff1a sudo nano /etc/sudoers ypw ALL =( ALL ) NOPASSWD:ALL # \u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c Ubuntu 22.04 \u53ca\u4ee5\u540e\uff1a /etc/sudoers \u5728 22.04 \u4e4b\u540e\u53d8\u5f97\u4e0d\u53ef\u5199\uff1a [ /etc/sudoers is meant to be read-only ] \u56e0\u6b64\u4f60\u9700\u8981\u5728 /etc/sudoers.d/ \u6587\u4ef6\u5939\u4e0b\u521b\u5efa\u81ea\u5df1\u7684\u6587\u4ef6\uff1a sudo nano /etc/sudoers.d/ypw ypw ALL=(ALL) NOPASSWD:ALL # \u5199\u5165\u5230\u6587\u4ef6\u4e2d \u914d\u7f6e apt \u6e90 \u5728\u4f7f\u7528 apt \u7684\u65f6\u5019\u6709\u53ef\u80fd\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u5b89\u88c5\u8fc7\u6162\u6216\u5931\u8d25\uff0c\u8fd9\u65f6\u5019\u53ef\u4ee5\u914d\u7f6e\u4e00\u4e9b apt \u6e90\uff1a https://mirror.tuna.tsinghua.edu.cn/help/ubuntu/ https://opsx.alibaba.com/mirror \u4e0b\u9762\u4ee5\u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u4e3a\u4f8b\uff1a sudo mv /etc/apt/sources.list /etc/apt/sources_backup.list sudo nano /etc/apt/sources.list # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\uff0c\u4fdd\u5b58 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse \u6dfb\u52a0\u597d\u4ee5\u540e\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u66f4\u65b0 apt \u4ee5\u540e\uff0c\u5b89\u88c5\u5176\u4ed6\u8f6f\u4ef6\u5305\u7684\u901f\u5ea6\u5c31\u4f1a\u53d8\u5feb\uff1a sudo apt update \u6062\u590d\u9ed8\u8ba4\u6e90\uff1a sudo mv /etc/apt/sources_backup.list /etc/apt/sources.list \u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4 \u5b89\u88c5 oh my zsh \u76f8\u6bd4\u9ed8\u8ba4\u7684 bash\uff0czsh \u6709\u4ee5\u4e0b\u51e0\u4e2a\u4f18\u70b9\uff1a \u5f53\u4f60\u4f7f\u7528 tab \u63d0\u793a\u7684\u65f6\u5019\uff0c\u5982\u679c\u6709\u591a\u4e2a\u5339\u914d\u9879\uff0c\u4f60\u53ef\u4ee5\u7528 tab \u8fdb\u884c\u5207\u6362 \u5f53\u4f60\u60f3\u4f7f\u7528\u4e00\u4e2a\u4e4b\u524d\u8f93\u5165\u8fc7\u7684\u547d\u4ee4\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u8f93\u5165\u9996\u5b57\u6bcd\uff0c\u7136\u540e\u6309\u4e0a\u65b9\u5411\u952e\u5207\u6362 \u5b89\u88c5 oh my zsh \u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u5b89\u88c5 zsh \u5b89\u88c5 oh my zsh \u5b8c\u6574\u547d\u4ee4\u5982\u4e0b\uff1a sudo apt install -y git curl zsh sh -c \" $( curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \" \u5e38\u7528\u547d\u4ee4 \u8fd9\u4e9b\u662f\u6211\u7684 \u5fc5\u5907\u547d\u4ee4 \uff0c\u4f60\u53ef\u4ee5\u6309\u7167\u81ea\u5df1\u7684\u9700\u8981\u5b89\u88c5\uff1a sudo apt install -y net-tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08apt\uff09 \u5b89\u88c5\u9a71\u52a8\u6709\u4e24\u79cd\u65b9\u6cd5\uff0c\u4e00\u79cd\u662f\u4f7f\u7528apt\u5b89\u88c5\uff0c\u4e00\u79cd\u662f\u76f4\u63a5\u4e0b\u8f7d\u9a71\u52a8\u5b89\u88c5\u3002\u6211\u4e00\u822c\u4f1a\u9009\u62e9\u76f4\u63a5\u4e0b\u8f7d\u9a71\u52a8\u3002 \u4f7f\u7528 apt \u5b89\u88c5\u9a71\u52a8 \u5b89\u88c5\u8fc7\u7a0b\u53ef\u4ee5\u53c2\u8003 TensorFlow \u7684\u6559\u7a0b\uff1a https://www.tensorflow.org/install/gpu \u4e0b\u9762\u662f\u6211\u5b89\u88c5\u7684\u547d\u4ee4\uff1a # Add NVIDIA package repositories wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.0.130-1_amd64.deb sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub sudo apt update wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb sudo apt install ./nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb sudo apt update # Install NVIDIA driver sudo aptitude install nvidia-driver-410 # Reboot. Check that GPUs are visible using the command: nvidia-smi \u5982\u679c\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u4e0b\u8f7d\u5f88\u6162\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u8ba9 apt \u4f7f\u7528\u4ee3\u7406\uff1a sudo nano /etc/apt/apt.conf # \u4e0b\u9762\u7684\u5185\u5bb9\u6309\u7167\u5b9e\u9645\u60c5\u51b5\u8fdb\u884c\u4fee\u6539 Acquire::http::Proxy \"http://192.168.8.246:1087\" ; \u4e3a\u4e86\u907f\u514d\u91cd\u542f\u4ee5\u540e\u9f20\u6807\u952e\u76d8\u6ca1\u53cd\u5e94\uff0c\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a sudo apt install --reinstall xserver-xorg-input-all \u6d4b\u8bd5\u663e\u5361 \u88c5\u597d\u7cfb\u7edf\u4ee5\u540e\u9700\u8981\u91cd\u65b0\u542f\u52a8\u673a\u5668\uff0c\u91cd\u542f\u4ee5\u540e\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u5373\u53ef\u6d4b\u8bd5\u663e\u5361\uff1a nvidia-smi \u5982\u679c\u80fd\u770b\u5230\u7c7b\u4f3c\u7684\u5185\u5bb9\u5c31\u8bf4\u660e\u663e\u5361\u9a71\u52a8\u88c5\u597d\u4e86\uff1a Fri Jan 15 21:15:14 2021 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 GeForce RTX 3080 Off | 00000000:01:00.0 On | N/A | | 31% 22C P8 6W / 320W | 183MiB / 10015MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | 0 N/A N/A 1151 G /usr/lib/xorg/Xorg 142MiB | | 0 N/A N/A 1454 G /usr/bin/gnome-shell 38MiB | +-----------------------------------------------------------------------------+ \u5b89\u88c5 CUDA \u548c cuDNN \u6ce8\u610f\uff1a \u6b64\u6b65\u9aa4\u9700\u4e0b\u8f7d\u8f83\u5927\u7684\u5b89\u88c5\u5305 PyTorch \u7528\u6237\u53ef\u4ee5\u4e0d\u5b89\u88c5 CUDA \u548c cuDNN sudo apt install --no-install-recommends \\ cuda-10-0 \\ libcudnn7 = 7 .6.0.64-1+cuda10.0 \\ libcudnn7-dev = 7 .6.0.64-1+cuda10.0 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \u5b89\u88c5\u597d\u4ee5\u540e\u8fd8\u9700\u8981 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u8fd9\u91cc\u6211\u4ee5 ~/.zshrc \u4e3a\u4f8b\uff1a nano ~/.zshrc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 export PATH = /usr/local/cuda/bin: $PATH export LD_LIBRARY_PATH = /usr/local/cuda/lib64: $LD_LIBRARY_PATH \u5b89\u88c5 TensorRT\uff08\u53ef\u9009\uff09 sudo apt update sudo apt install -y --no-install-recommends libnvinfer5 = 5 .1.5-1+cuda10.0 sudo apt install -y --no-install-recommends libnvinfer-dev = 5 .1.5-1+cuda10.0 \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08run\uff09 \u4e0b\u8f7d\u9a71\u52a8 \u9996\u5148\u53bb\u5b98\u7f51\u4e0b\u8f7d\u9a71\u52a8\uff1a https://www.nvidia.com/Download/index.aspx?lang=cn \u6709\u4e0b\u9762\u51e0\u79cd\u65b9\u6cd5\u53ef\u4ee5\u4e0b\u8f7d\uff1a \u5728 Ubuntu \u673a\u5668\u4e0a\u76f4\u63a5\u4f7f\u7528\u6d4f\u89c8\u5668\u4e0b\u8f7d \u5728\u81ea\u5df1\u673a\u5668\u4e0a\u4e0b\u8f7d\uff0c\u7136\u540e\u901a\u8fc7 scp \u4f20\u5230 Ubuntu \u673a\u5668\u4e0a \u5728\u81ea\u5df1\u673a\u5668\u4e0a\u627e\u5230\u4e0b\u8f7d\u5730\u5740\uff0c\u7136\u540e\u5728 Ubuntu \u673a\u5668\u4e0a\u4f7f\u7528 wget \u547d\u4ee4\u4e0b\u8f7d \u4ee5\u4e0a\u65b9\u6cd5\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u60c5\u51b5\u9009\u62e9\uff0c\u8fd9\u91cc\u6211\u9009\u62e9\u7b2c\u4e09\u79cd\u65b9\u6cd5\uff1a wget https://cn.download.nvidia.cn/XFree86/Linux-x86_64/450.80.02/NVIDIA-Linux-x86_64-450.80.02.run \u5c4f\u853d Nouveau \u5982\u679c\u4f60\u6ca1\u6709\u5c4f\u853d\uff0c\u5c31\u4f1a\u51fa\u73b0\u4ee5\u4e0b\u63d0\u793a\uff1a ERROR: The Nouveau kernel driver is currently in use by your system. This driver is incompatible with the NVIDIA driver, and must be disabled before proceeding. Please consult the NVIDIA driver README and your Linux distribution's documentation for details on how to correctly disable the Nouveau kernel driver. \u547d\u4ee4\uff1a sudo nano /etc/modprobe.d/blacklist-nouveau.conf # \u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9 blacklist nouveau options nouveau modeset = 0 # \u4fdd\u5b58 sudo update-initramfs -u sudo reboot \u5b89\u88c5\u5fc5\u8981\u7684\u7f16\u8bd1\u5de5\u5177 \u5982\u679c\u6ca1\u6709\u5b89\u88c5 gcc \u7b49\u7f16\u8bd1\u5de5\u5177\uff0c\u5c31\u4f1a\u51fa\u73b0\u4ee5\u4e0b\u63d0\u793a\uff1a ERROR: Unable to find the development tool cc in your path; please make sure that you have the package 'gcc' installed. If gcc is installed on your system, then please check that cc is in your PATH. \u547d\u4ee4\uff1a sudo apt install -y build-essential gcc g++ make binutils linux-headers- ` uname -r ` \u5b89\u88c5\u663e\u5361\u9a71\u52a8 sudo bash NVIDIA-Linux-x86_64-450.80.02.run \u5b89\u88c5\u6b65\u9aa4\u5f88\u7b80\u5355\uff0c\u4e00\u76f4\u4e0b\u4e00\u6b65\u5c31\u597d\u4e86\u3002 \u6d4b\u8bd5\u663e\u5361 nvidia-smi \u5982\u679c\u80fd\u770b\u5230\u7c7b\u4f3c\u7684\u5185\u5bb9\u5c31\u8bf4\u660e\u663e\u5361\u9a71\u52a8\u88c5\u597d\u4e86\uff1a Fri Jan 15 21:15:14 2021 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 GeForce RTX 3080 Off | 00000000:01:00.0 On | N/A | | 31% 22C P8 6W / 320W | 183MiB / 10015MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | 0 N/A N/A 1151 G /usr/lib/xorg/Xorg 142MiB | | 0 N/A N/A 1454 G /usr/bin/gnome-shell 38MiB | +-----------------------------------------------------------------------------+ \u5b89\u88c5 CUDA \u548c cuDNN \u7531\u4e8e\u4e0d\u540c\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684 CUDA \u548c cuDNN \u7248\u672c\u4f9d\u8d56\u662f\u4e0d\u540c\u7684\uff0c\u6240\u4ee5\u8bf7\u6309\u7167\u4f60\u6240\u9700\u8981\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u5b98\u7f51\u4e0a\u7684\u8bf4\u660e\u4e3a\u51c6\u3002\u5173\u4e8e CUDA \u7248\u672c\u3001cuDNN\u7248\u672c\u4ee5\u53ca\u6df1\u5ea6\u5b66\u4e60\u73af\u5883\u7684\u4ecb\u7ecd\uff0c\u8bf7\u770b Ubuntu \u73af\u5883 \u3002 \u63d0\u793a\uff1aPyTorch \u7528\u6237\u53ef\u4ee5\u4e0d\u5b89\u88c5 CUDA \u548c cuDNN\u3002 \u5b89\u88c5 CUDA 10.0 \u7531\u4e8e\u6b64\u5b89\u88c5\u5305\u6bd4\u8f83\u5927\uff0c\u5efa\u8bae\u4f7f\u7528 aria2c \u4e0b\u8f7d\uff1a aria2c -x 16 https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux \u4e0b\u8f7d\u597d\u4e86\u4ee5\u540e\uff0c\u76f4\u63a5\u8fd0\u884c\u5b89\u88c5\u5373\u53ef\uff1a sudo bash cuda_10.0.130_410.48_linux.run # \u6309 q \u9000\u51fa EULA NVIDIA CUDA Toolkit Do you accept the previously read EULA? accept/decline/quit: accept Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 410 .48? ( y ) es/ ( n ) o/ ( q ) uit: n Install the CUDA 10 .0 Toolkit? ( y ) es/ ( n ) o/ ( q ) uit: y Enter Toolkit Location [ default is /usr/local/cuda-10.0 ] : Do you want to install a symbolic link at /usr/local/cuda? ( y ) es/ ( n ) o/ ( q ) uit: y Install the CUDA 10 .0 Samples? ( y ) es/ ( n ) o/ ( q ) uit: n Installing the CUDA Toolkit in /usr/local/cuda-10.0 ... =========== = Summary = =========== Driver: Not Selected Toolkit: Installed in /usr/local/cuda-10.0 Samples: Not Selected \u53ef\u4ee5\u6309\u7167\u81ea\u5df1\u7684\u9700\u8981\u8bf7\u914d\u7f6e\u4e0b\u9762\u7684\u9009\u9879\uff0c\u6bd4\u5982\u4f60\u60f3\u5b66\u4e60\u4f7f\u7528 C/C++ \u7f16\u5199 CUDA \u7a0b\u5e8f\uff0c\u53ef\u4ee5\u5b89\u88c5 Samples\u3002 \u6ce8\u610f\uff1a Please make sure that PATH includes /usr/local/cuda-10.0/bin LD_LIBRARY_PATH includes /usr/local/cuda-10.0/lib64, or, add /usr/local/cuda-10.0/lib64 to /etc/ld.so.conf and run ldconfig as root \u9700\u8981\u6309\u7167\u4e0a\u9762\u7684\u6307\u793a \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u8fd9\u91cc\u6211\u4ee5 ~/.zshrc \u4e3a\u4f8b\uff1a nano ~/.zshrc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 export PATH = /usr/local/cuda/bin: $PATH export LD_LIBRARY_PATH = /usr/local/cuda/lib64: $PATH \u5b89\u88c5 cuDNN \u540c\u6837\uff0c\u4e0b\u8f7d cudnn-10.0-linux-x64-v7.6.0.64.tgz\uff1a aria2c -x 16 http://developer.download.nvidia.com/compute/redist/cudnn/v7.6.0/cudnn-10.0-linux-x64-v7.6.0.64.tgz \u7136\u540e\u5b89\u88c5\u5230 /usr/local \u76ee\u5f55\u4e0b\uff1a sudo tar -xzf cudnn-10.0-linux-x64-v7.6.0.64.tgz -C /usr/local \u5b89\u88c5 Anaconda \u548c Python \u5e93 \u5b89\u88c5 Anaconda \u5b89\u88c5 Anaconda \u548c Python \u5e93\u7684\u6b65\u9aa4\u90fd\u5df2\u7ecf\u5199\u5728\u4e86 Pyhton \u73af\u5883 \uff0c\u8fd9\u91cc\u4ec5\u4ec5\u5c55\u793a\u76f8\u5173\u547d\u4ee4\uff1a aria2c -x 16 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.03-Linux-x86_64.sh bash Anaconda3-2019.03-Linux-x86_64.sh # \u56de\u8f66\uff0c\u7136\u540e\u6309 q \u9000\u51fa EULA Do you accept the license terms? [ yes | no ] [ no ] >>> yes Anaconda3 will now be installed into this location: /home/ypw/anaconda3 - Press ENTER to confirm the location - Press CTRL-C to abort the installation - Or specify a different location below [ /home/ypw/anaconda3 ] >>> PREFIX = /home/ypw/anaconda3 installing: python-3.7.3-h0371630_0 ... Python 3 .7.3 installing: conda-env-2.6.0-1 ... installing: blas-1.0-mkl ... ...... installing: anaconda-2019.03-py37_0 ... installation finished. Do you wish the installer to initialize Anaconda3 by running conda init? [ yes | no ] [ no ] >>> yes ...... Thank you for installing Anaconda3! \u5b89\u88c5\u5b8c\u6210\u4ee5\u540e\uff0c\u4f60\u53ef\u80fd\u8fd8\u9700\u8981 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \u3002 ~/anaconda3/bin/conda init # \u5982\u679c\u4f60\u7528\u7684\u7ec8\u7aef\u662fzsh ~/anaconda3/bin/conda init zsh \u914d\u7f6e\u597d\u4ee5\u540e\uff0c\u53ef\u4ee5\u91cd\u542f\u673a\u5668\uff0c\u6216\u8005\u4f7f\u7528 source ~/.zshrc \u66f4\u65b0\u73af\u5883\u53d8\u91cf \u3002 \u914d\u7f6e pip \u6e90 \u5728\u4f7f\u7528 pip \u7684\u65f6\u5019\u6709\u53ef\u80fd\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u5b89\u88c5\u8fc7\u6162\u6216\u5931\u8d25\uff0c\u8fd9\u65f6\u5019\u53ef\u4ee5 \u914d\u7f6e\u56fd\u5185\u7684 pip \u6e90 \uff1a https://developer.aliyun.com/mirror/pypi https://mirror.tuna.tsinghua.edu.cn/help/pypi/ \u4e0b\u9762\u4ee5\u963f\u91cc\u4e91\u4e3a\u4f8b\uff1a pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ Python \u5e93 \u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5b89\u88c5 \u5e38\u7528 Python \u5e93 \uff1a pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx xlrd openpyxl \u6ce8\u610f\uff1a\u5982\u679c\u662f 30 \u7cfb\u5217\u7684\u663e\u5361\uff0c\u6bd4\u5982 3080\u30013090\uff0c\u9700\u8981\u4f7f\u7528CUDA11\u6216\u4ee5\u4e0a\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\uff0c\u6bd4\u5982 PyTorch \u76ee\u524d\u662f\u8fd9\u6837\u5b89\u88c5\u7684\uff1a pip install torch == 1 .7.1+cu110 torchvision == 0 .8.2+cu110 torchaudio === 0 .7.2 -f https://download.pytorch.org/whl/torch_stable.html \u6d4b\u8bd5 PyTorch import torch dummy = torch . zeros ( 1 , 3 , 5 , 5 ) . cuda () conv = torch . nn . Conv2d ( in_channels = 3 , out_channels = 1 , kernel_size = 3 ) . cuda () print ( conv ( dummy )) \u671f\u671b\u8f93\u51fa\uff1a tensor ([[[[ 0.0443 , 0.0443 , 0.0443 ], [ 0.0443 , 0.0443 , 0.0443 ], [ 0.0443 , 0.0443 , 0.0443 ]]]], device = 'cuda:0' , grad_fn =< CudnnConvolutionBackward > ) \u6d4b\u8bd5 TensorFlow import tensorflow as tf mnist = tf.keras.datasets.mnist ( x_train, y_train ) , ( x_test, y_test ) = mnist.load_data () x_train, x_test = x_train / 255 .0, x_test / 255 .0 model = tf.keras.models.Sequential ([ tf.keras.layers.Flatten ( input_shape =( 28 , 28 )) , tf.keras.layers.Dense ( 512 , activation = tf.nn.relu ) , tf.keras.layers.Dropout ( 0 .2 ) , tf.keras.layers.Dense ( 10 , activation = tf.nn.softmax ) ]) model.compile ( optimizer = 'adam' , loss = 'sparse_categorical_crossentropy' , metrics =[ 'accuracy' ]) model.fit ( x_train, y_train, epochs = 5 ) model.evaluate ( x_test, y_test ) \u671f\u671b\u8f93\u51fa\uff08\u6ce8\u610f\u91cc\u9762\u7684 GeForce GTX 1080 Ti\uff09 \uff1a >>> model.fit(x_train, y_train, epochs=5) 2019-07-21 17:18:16.455944: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA 2019-07-21 17:18:16.460577: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3599995000 Hz 2019-07-21 17:18:16.461013: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e83e4f40 executing computations on platform Host. Devices: 2019-07-21 17:18:16.461032: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): , 2019-07-21 17:18:16.462663: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcuda.so.1 2019-07-21 17:18:16.915819: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.916435: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e78c9a40 executing computations on platform CUDA. Devices: 2019-07-21 17:18:16.916504: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): GeForce GTX 1080 Ti, Compute Capability 6.1 2019-07-21 17:18:16.916782: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.918218: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties: name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.683 pciBusID: 0000:0b:00.0 2019-07-21 17:18:16.918581: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0 2019-07-21 17:18:16.920971: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0 2019-07-21 17:18:16.922961: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcufft.so.10.0 2019-07-21 17:18:16.923461: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcurand.so.10.0 2019-07-21 17:18:16.926265: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusolver.so.10.0 2019-07-21 17:18:16.928450: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusparse.so.10.0 2019-07-21 17:18:16.932250: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudnn.so.7 2019-07-21 17:18:16.932341: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.932899: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.933392: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0 2019-07-21 17:18:16.933426: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0 2019-07-21 17:18:16.934335: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix: 2019-07-21 17:18:16.934353: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1187] 0 2019-07-21 17:18:16.934363: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1200] 0: N 2019-07-21 17:18:16.934444: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.934988: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.935504: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 10481 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:0b:00.0, compute capability: 6.1) Epoch 1/5 2019-07-21 17:18:17.663035: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0 60000/60000 [==============================] - 3s 49us/sample - loss: 0.2209 - acc: 0.9344 Epoch 2/5import torch x = torch.rand(5, 3) print(x) 60000/60000 [==============================] - 2s 39us/sample - loss: 0.0968 - acc: 0.9707 Epoch 3/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0696 - acc: 0.9779 Epoch 4/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0537 - acc: 0.9826 Epoch 5/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0428 - acc: 0.9863 >>> model.evaluate(x_test, y_test) 10000/10000 [==============================] - 0s 24us/sample - loss: 0.0698 - acc: 0.9804 [0.06983174340333789, 0.9804]","title":"Ubuntu \u88c5\u673a\u6b65\u9aa4"},{"location":"ubuntu-install-guide/#ubuntu","text":"\u5b89\u88c5 Ubuntu \u914d\u7f6e ssh \u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90\uff08\u63a8\u8350\uff09 \u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4\uff08\u63a8\u8350\uff09 \u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08\u5206\u4e3a apt \u548c run \u4e24\u79cd\u5b89\u88c5\u65b9\u5f0f\uff09 \u5b89\u88c5 Anaconda \u548c Python \u5e93","title":"Ubuntu \u88c5\u673a\u6b65\u9aa4"},{"location":"ubuntu-install-guide/#_1","text":"Ubuntu 22.04 \u4ee5\u524d\uff1a # \u6dfb\u52a0 sudo \u514d\u5bc6\u7801 if [ [ $ ( sudo grep -L $USER / etc / sudoers ) ] ]; then echo \"Add $USER to sudoers\" echo \"$USER ALL=(ALL) NOPASSWD:ALL\" | sudo tee -a / etc / sudoers ; fi Ubuntu 22.04 \u53ca\u4ee5\u540e\uff1a FILE = \" /etc/sudoers.d/$USER \" if [ ! - f \" $FILE \" ] ; then echo \" Create $FILE and add sudo permission \" echo \" $USER ALL=(ALL) NOPASSWD:ALL \" | sudo tee \" $FILE \" fi # \u5347\u7ea7\u7cfb\u7edf sudo apt update sudo apt upgrade -y # \u5b89\u88c5\u5e38\u7528\u547d\u4ee4\u548c oh-my-zsh sudo apt install - y openssh - server git curl zsh net - tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop cifs - utils landscape - common p7zip - full sh - c \"$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)\" # \u5b89\u88c5 Python \u73af\u5883 wget https://mirrors.bfsu.edu.cn/anaconda/miniconda/Miniconda3-py310_23.3.1-0-Linux-x86_64.sh bash Miniconda3-py310_23.3.1-0-Linux-x86_64.sh -b ~/miniconda3/bin/conda init bash ~/miniconda3/bin/conda init zsh # reboot your terminal ~/ miniconda3 / bin / conda activate # pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ # pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pip config set global . index - url https : // mirrors . bfsu . edu . cn / pypi / web / simple pip install torch == 2.1 . 1 + cu118 torchvision == 0.16 . 1 + cu118 -- index - url https : // download . pytorch . org / whl / cu118 pip install jupyter jupyter_contrib_nbextensions numpy pandas flask scikit - image scikit - learn matplotlib opencv - python pillow tqdm openpyxl ninja xtcocotools json_tricks munkres shapely ftfy pytest regex pyyaml yapf cython build twine memory_profiler pip install openmim mim install mmpretrain mmdet mmpose mmsegmentation \u5b89\u88c5 CUDA\uff1a Ubuntu 18.04\uff1a # \u5b89\u88c5 CUDA 11.8\uff0cubuntu18.04 wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu1804 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda - 11 - 8 Ubuntu 20.04\uff1a wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu2004 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda11 - 8 Ubuntu 22.04 \u53c2\u8003\u94fe\u63a5 \uff1a wget https : // developer . download . nvidia . com / compute / cuda / repos / ubuntu2204 / x86_64 / cuda - keyring_1 . 0 - 1 _all . deb sudo dpkg - i cuda - keyring_1 . 0 - 1 _all . deb sudo apt - get update sudo apt - get - y install cuda - 11 - 8 \u5b89\u88c5\u6307\u5b9a\u7248\u672c\u7684 cudnn\uff1a sudo apt install libcudnn8 = 8 .7.0.84-1+cuda11.8 libcudnn8-dev = 8 .7.0.84-1+cuda11.8 \u6dfb\u52a0 CUDA \u73af\u5883\u53d8\u91cf\uff1a # CUDA \u73af\u5883\u53d8\u91cf if [[ $ ( grep - L \"cuda\" ~/. bashrc ) ]]; then echo \"Add CUDA environment to ~/.bashrc\" echo \"export PATH=/usr/local/cuda/bin:\\$PATH\" | tee - a ~/. bashrc ; echo \"export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\\$LD_LIBRARY_PATH\" | tee - a ~/. bashrc ; fi if [[ $ ( grep - L \"cuda\" ~/. zshrc ) ]]; then echo \"Add CUDA environment to ~/.zshrc\" echo \"export PATH=/usr/local/cuda/bin:\\$PATH\" | tee - a ~/. zshrc ; echo \"export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\\$LD_LIBRARY_PATH\" | tee - a ~/. zshrc ; fi \u5b89\u88c5 mmdet\uff1a mim install mmdet","title":"\u811a\u672c\u5f0f\u88c5\u673a"},{"location":"ubuntu-install-guide/#ubuntu_1","text":"\u4ee5\u4e0b\u662f Ubuntu \u5b98\u65b9\u7f51\u7ad9\u4e0a\u7684\u6559\u7a0b\uff1a \u5728 Windows \u4e0a\u5236\u4f5c Ubuntu \u7cfb\u7edf\u76d8 \u5728 macOS \u4e0a\u5236\u4f5c Ubuntu \u7cfb\u7edf\u76d8 \u5b89\u88c5 Ubuntu \u76ee\u524d\u6211\u5b89\u88c5\u7684\u7248\u672c\u662f Ubuntu 18.04 \u5982\u679c\u9047\u5230\u7f51\u7edc\u95ee\u9898\uff0c\u53ef\u4ee5\u4f7f\u7528\u6e05\u534e\u5927\u5b66\u7684\u955c\u50cf\uff1a https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/18.04.4/ubuntu-18.04.4-desktop-amd64.iso \u5982\u679c\u4e0a\u9762\u7684\u94fe\u63a5\u5931\u6548\u4e86\uff0c\u8bf4\u660e ubuntu \u51fa\u65b0\u7248\u4e86\uff0c\u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u67e5\u627e\u65b0\u7248\uff1a https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/ \u3002","title":"\u5b89\u88c5 Ubuntu"},{"location":"ubuntu-install-guide/#ssh","text":"","title":"\u914d\u7f6e ssh"},{"location":"ubuntu-install-guide/#openssh-server","text":"\u88c5\u597d Ubuntu \u4ee5\u540e\uff0c\u4e3a\u4e86\u80fd\u591f\u65b9\u4fbf\u5730\u5728\u5176\u4ed6\u7ec8\u7aef\u4e0a\u8fdc\u7a0b\u8fde\u63a5\uff0c\u5b89\u88c5\u5404\u79cd\u8f6f\u4ef6\uff0c\u6211\u4e00\u822c\u4f1a\u5148\u88c5 openssh-server\u3002 sudo apt update sudo apt install openssh-server \u88c5\u597d\u4e86\u4ee5\u540e\uff0c\u5c31\u53ef\u4ee5\u5728\u7ec8\u7aef\u91cc\u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\u8fde\u63a5\u670d\u52a1\u5668\u3002 ssh 192 .168.8.65 \u4f7f\u7528\u5230\u7684\u547d\u4ee4\uff1a apt \u3001 ssh","title":"\u5b89\u88c5 openssh-server"},{"location":"ubuntu-install-guide/#ssh-keygen-ssh-key","text":"\u76ee\u524d\u4f7f\u7528\u5bc6\u7801\u4e0a\u4e0d\u5982\u4f7f\u7528 key \u5b89\u5168\u7684\uff0c\u56e0\u4e3a key \u7684\u957f\u5ea6\u901a\u5e38\u662f 2048 \u6216 4096 \u4f4d\uff0c\u8fdc\u8d85\u666e\u901a\u7684\u5bc6\u7801\u3002\u8fd9\u91cc\u5efa\u8bae\u6309\u7167 GitHub \u5b98\u65b9\u7f51\u7ad9\u4e0a\u7684\u6559\u7a0b \u751f\u6210\u65b0 SSH \u5bc6\u94a5\u5e76\u6dfb\u52a0\u5230 ssh-agent \uff0c\u8fd9\u6837\u4e0d\u4ec5\u53ef\u4ee5\u7528\u4e8e\u767b\u5f55 Linux \u673a\u5668\uff0c\u4e5f\u53ef\u4ee5\u7528\u4e8e git\u3002 \u4f7f\u7528 ssh-keygen \u751f\u6210\u4e86\u5bc6\u94a5\u4ee5\u540e\uff0c\u4f60\u4f1a\u5f97\u5230\u4e24\u4e2a\u6587\u4ef6\uff1a ~/.ssh/id_rsa ~/.ssh/id_rsa.pub \u5176\u4e2d id_rsa \u662f\u79c1\u94a5\uff0c id_rsa.pub \u662f\u516c\u94a5\u3002\u4e0d\u8981\u628a\u79c1\u94a5\u53d1\u7ed9\u4efb\u4f55\u4eba\u3002 \u200b\u516c\u94a5\u901a\u5e38\u4e0a\u8fd9\u6837\u7684\u6587\u672c\uff1a ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcfQD4nnaQrgC003C0ReAYqrm6XKEchuM6DwkNtHzRs2YhLolH6fEohWAp0mlW9yzQl258lA+FdoH51ONmvGUx/2Y953A6ujHrt7dOIpOkYW5HT6Rmvlwk+3uRmVNQqZTJeRWdblcSHmYY1fi1miawONZiVoLW14xhyH5bOwgwY/GB2yTaffDby451RLT5kQ7LHqiDJtWiRQekR5tKDKZ7mBhKZIKYLOoqAayCHw2scJYsgtw2tPt0/y7BlxO+RuDwuD2WOnthe1ewbwAbbTN17HiLvBd/MIWtVDoGGq6jdNDjNDNbTs8H2VohTc2mNtOOlycN6yzf3ZKZTN6/hNtl ypw@yangpeiendeiMac","title":"\u4f7f\u7528 ssh-keygen \u751f\u6210\u4e00\u4e2a ssh key"},{"location":"ubuntu-install-guide/#ubuntu-ssh-key","text":"\u9996\u5148\u4f7f\u7528\u5bc6\u7801\u767b\u5f55\u521a\u624d\u7684\u673a\u5668\uff1a ssh 192 .168.8.65 \u7136\u540e\u521b\u5efa ~/.ssh \u76ee\u5f55\uff0c\u5e76\u4e14\u521b\u5efa ~/.ssh/authorized_keys \u6587\u4ef6\uff0c\u914d\u7f6e\u597d\u76f8\u5e94\u7684\u6743\u9650\uff1a mkdir -p ~/.ssh touch ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys nano ~/.ssh/authorized_keys # \u6dfb\u52a0\u4f60\u7684\u516c\u94a5\uff0c\u5982 ssh-rsa AAAA... \u628a\u521a\u624d\u751f\u6210\u7684\u516c\u94a5 id_rsa.pub \u6dfb\u52a0\u5230 ~/.ssh/authorized_keys \u91cc\uff0c\u5982\u679c\u6587\u4ef6\u5df2\u7ecf\u6709\u5185\u5bb9\uff0c\u5c31\u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c\u3002\u8fd9\u6837\u4ee5\u540e \u6bcf\u6b21\u4f7f\u7528 ssh \u767b\u5f55\u673a\u5668\u90fd\u4e0d\u9700\u8981\u518d\u8f93\u5165\u5bc6\u7801\u4e86 \u3002 \u4f7f\u7528\u5230\u7684\u547d\u4ee4\uff1a mkdir \u3001 touch \u3001 chmod \u3001 nano","title":"\u5728 Ubuntu \u670d\u52a1\u5668\u4e0a\u6dfb\u52a0\u521a\u624d\u751f\u6210\u7684 ssh key"},{"location":"ubuntu-install-guide/#_2","text":"\u7531\u4e8e\u5bc6\u7801\u767b\u5f55\u5b58\u5728\u4e0d\u5b89\u5168\u56e0\u7d20\uff0c\u6bd4\u5982\u66b4\u9732\u5728\u516c\u7f51\u7684 IP \u4f1a\u88ab\u626b\u63cf\uff0c\u800c key \u662f\u76f8\u5bf9\u5b89\u5168\u7684\uff0c\u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u7981\u6b62\u4e0d\u5b89\u5168\u7684\u5bc6\u7801\u767b\u5f55\uff1a sudo nano /etc/ssh/sshd_config PasswordAuthentication no # \u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c","title":"\u7981\u6b62\u5bc6\u7801\u767b\u5f55"},{"location":"ubuntu-install-guide/#sudo-apt","text":"","title":"\u914d\u7f6e sudo \u514d\u5bc6\u7801 \u548c apt \u6e90"},{"location":"ubuntu-install-guide/#sudo","text":"Ubuntu 22.04 \u4ee5\u524d\uff1a \u7531\u4e8e\u5b89\u88c5\u9a71\u52a8\u7b49\u64cd\u4f5c\u9700\u8981 sudo \u6743\u9650\uff0c\u4e3a\u4e86\u907f\u514d\u9891\u7e41\u8f93\u5165\u5bc6\u7801\uff0c\u53ef\u4ee5\u914d\u7f6e sudo \u514d\u5bc6\u7801\uff1a sudo nano /etc/sudoers ypw ALL =( ALL ) NOPASSWD:ALL # \u6dfb\u52a0\u5728\u6700\u540e\u4e00\u884c Ubuntu 22.04 \u53ca\u4ee5\u540e\uff1a /etc/sudoers \u5728 22.04 \u4e4b\u540e\u53d8\u5f97\u4e0d\u53ef\u5199\uff1a [ /etc/sudoers is meant to be read-only ] \u56e0\u6b64\u4f60\u9700\u8981\u5728 /etc/sudoers.d/ \u6587\u4ef6\u5939\u4e0b\u521b\u5efa\u81ea\u5df1\u7684\u6587\u4ef6\uff1a sudo nano /etc/sudoers.d/ypw ypw ALL=(ALL) NOPASSWD:ALL # \u5199\u5165\u5230\u6587\u4ef6\u4e2d","title":"\u914d\u7f6e sudo \u514d\u5bc6\u7801"},{"location":"ubuntu-install-guide/#apt","text":"\u5728\u4f7f\u7528 apt \u7684\u65f6\u5019\u6709\u53ef\u80fd\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u5b89\u88c5\u8fc7\u6162\u6216\u5931\u8d25\uff0c\u8fd9\u65f6\u5019\u53ef\u4ee5\u914d\u7f6e\u4e00\u4e9b apt \u6e90\uff1a https://mirror.tuna.tsinghua.edu.cn/help/ubuntu/ https://opsx.alibaba.com/mirror \u4e0b\u9762\u4ee5\u6e05\u534e\u5927\u5b66\u5f00\u6e90\u8f6f\u4ef6\u955c\u50cf\u7ad9\u4e3a\u4f8b\uff1a sudo mv /etc/apt/sources.list /etc/apt/sources_backup.list sudo nano /etc/apt/sources.list # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\uff0c\u4fdd\u5b58 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse \u6dfb\u52a0\u597d\u4ee5\u540e\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u66f4\u65b0 apt \u4ee5\u540e\uff0c\u5b89\u88c5\u5176\u4ed6\u8f6f\u4ef6\u5305\u7684\u901f\u5ea6\u5c31\u4f1a\u53d8\u5feb\uff1a sudo apt update \u6062\u590d\u9ed8\u8ba4\u6e90\uff1a sudo mv /etc/apt/sources_backup.list /etc/apt/sources.list","title":"\u914d\u7f6e apt \u6e90"},{"location":"ubuntu-install-guide/#oh-my-zsh","text":"","title":"\u5b89\u88c5 oh my zsh \u4ee5\u53ca\u5e38\u7528\u547d\u4ee4"},{"location":"ubuntu-install-guide/#oh-my-zsh_1","text":"\u76f8\u6bd4\u9ed8\u8ba4\u7684 bash\uff0czsh \u6709\u4ee5\u4e0b\u51e0\u4e2a\u4f18\u70b9\uff1a \u5f53\u4f60\u4f7f\u7528 tab \u63d0\u793a\u7684\u65f6\u5019\uff0c\u5982\u679c\u6709\u591a\u4e2a\u5339\u914d\u9879\uff0c\u4f60\u53ef\u4ee5\u7528 tab \u8fdb\u884c\u5207\u6362 \u5f53\u4f60\u60f3\u4f7f\u7528\u4e00\u4e2a\u4e4b\u524d\u8f93\u5165\u8fc7\u7684\u547d\u4ee4\u7684\u65f6\u5019\uff0c\u53ea\u9700\u8981\u8f93\u5165\u9996\u5b57\u6bcd\uff0c\u7136\u540e\u6309\u4e0a\u65b9\u5411\u952e\u5207\u6362 \u5b89\u88c5 oh my zsh \u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u5b89\u88c5 zsh \u5b89\u88c5 oh my zsh \u5b8c\u6574\u547d\u4ee4\u5982\u4e0b\uff1a sudo apt install -y git curl zsh sh -c \" $( curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh ) \"","title":"\u5b89\u88c5 oh my zsh"},{"location":"ubuntu-install-guide/#_3","text":"\u8fd9\u4e9b\u662f\u6211\u7684 \u5fc5\u5907\u547d\u4ee4 \uff0c\u4f60\u53ef\u4ee5\u6309\u7167\u81ea\u5df1\u7684\u9700\u8981\u5b89\u88c5\uff1a sudo apt install -y net-tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop","title":"\u5e38\u7528\u547d\u4ee4"},{"location":"ubuntu-install-guide/#nvidia-cuda-cudnnapt","text":"\u5b89\u88c5\u9a71\u52a8\u6709\u4e24\u79cd\u65b9\u6cd5\uff0c\u4e00\u79cd\u662f\u4f7f\u7528apt\u5b89\u88c5\uff0c\u4e00\u79cd\u662f\u76f4\u63a5\u4e0b\u8f7d\u9a71\u52a8\u5b89\u88c5\u3002\u6211\u4e00\u822c\u4f1a\u9009\u62e9\u76f4\u63a5\u4e0b\u8f7d\u9a71\u52a8\u3002","title":"\u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08apt\uff09"},{"location":"ubuntu-install-guide/#apt_1","text":"\u5b89\u88c5\u8fc7\u7a0b\u53ef\u4ee5\u53c2\u8003 TensorFlow \u7684\u6559\u7a0b\uff1a https://www.tensorflow.org/install/gpu \u4e0b\u9762\u662f\u6211\u5b89\u88c5\u7684\u547d\u4ee4\uff1a # Add NVIDIA package repositories wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.0.130-1_amd64.deb sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub sudo apt update wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb sudo apt install ./nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb sudo apt update # Install NVIDIA driver sudo aptitude install nvidia-driver-410 # Reboot. Check that GPUs are visible using the command: nvidia-smi \u5982\u679c\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u4e0b\u8f7d\u5f88\u6162\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u8ba9 apt \u4f7f\u7528\u4ee3\u7406\uff1a sudo nano /etc/apt/apt.conf # \u4e0b\u9762\u7684\u5185\u5bb9\u6309\u7167\u5b9e\u9645\u60c5\u51b5\u8fdb\u884c\u4fee\u6539 Acquire::http::Proxy \"http://192.168.8.246:1087\" ; \u4e3a\u4e86\u907f\u514d\u91cd\u542f\u4ee5\u540e\u9f20\u6807\u952e\u76d8\u6ca1\u53cd\u5e94\uff0c\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff1a sudo apt install --reinstall xserver-xorg-input-all","title":"\u4f7f\u7528 apt \u5b89\u88c5\u9a71\u52a8"},{"location":"ubuntu-install-guide/#_4","text":"\u88c5\u597d\u7cfb\u7edf\u4ee5\u540e\u9700\u8981\u91cd\u65b0\u542f\u52a8\u673a\u5668\uff0c\u91cd\u542f\u4ee5\u540e\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u5373\u53ef\u6d4b\u8bd5\u663e\u5361\uff1a nvidia-smi \u5982\u679c\u80fd\u770b\u5230\u7c7b\u4f3c\u7684\u5185\u5bb9\u5c31\u8bf4\u660e\u663e\u5361\u9a71\u52a8\u88c5\u597d\u4e86\uff1a Fri Jan 15 21:15:14 2021 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 GeForce RTX 3080 Off | 00000000:01:00.0 On | N/A | | 31% 22C P8 6W / 320W | 183MiB / 10015MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | 0 N/A N/A 1151 G /usr/lib/xorg/Xorg 142MiB | | 0 N/A N/A 1454 G /usr/bin/gnome-shell 38MiB | +-----------------------------------------------------------------------------+","title":"\u6d4b\u8bd5\u663e\u5361"},{"location":"ubuntu-install-guide/#cuda-cudnn","text":"\u6ce8\u610f\uff1a \u6b64\u6b65\u9aa4\u9700\u4e0b\u8f7d\u8f83\u5927\u7684\u5b89\u88c5\u5305 PyTorch \u7528\u6237\u53ef\u4ee5\u4e0d\u5b89\u88c5 CUDA \u548c cuDNN sudo apt install --no-install-recommends \\ cuda-10-0 \\ libcudnn7 = 7 .6.0.64-1+cuda10.0 \\ libcudnn7-dev = 7 .6.0.64-1+cuda10.0","title":"\u5b89\u88c5 CUDA \u548c cuDNN"},{"location":"ubuntu-install-guide/#_5","text":"\u5b89\u88c5\u597d\u4ee5\u540e\u8fd8\u9700\u8981 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u8fd9\u91cc\u6211\u4ee5 ~/.zshrc \u4e3a\u4f8b\uff1a nano ~/.zshrc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 export PATH = /usr/local/cuda/bin: $PATH export LD_LIBRARY_PATH = /usr/local/cuda/lib64: $LD_LIBRARY_PATH","title":"\u914d\u7f6e\u73af\u5883\u53d8\u91cf"},{"location":"ubuntu-install-guide/#tensorrt","text":"sudo apt update sudo apt install -y --no-install-recommends libnvinfer5 = 5 .1.5-1+cuda10.0 sudo apt install -y --no-install-recommends libnvinfer-dev = 5 .1.5-1+cuda10.0","title":"\u5b89\u88c5 TensorRT\uff08\u53ef\u9009\uff09"},{"location":"ubuntu-install-guide/#nvidia-cuda-cudnnrun","text":"","title":"\u5b89\u88c5 NVIDIA \u9a71\u52a8\u3001CUDA \u548c cuDNN\uff08run\uff09"},{"location":"ubuntu-install-guide/#_6","text":"\u9996\u5148\u53bb\u5b98\u7f51\u4e0b\u8f7d\u9a71\u52a8\uff1a https://www.nvidia.com/Download/index.aspx?lang=cn \u6709\u4e0b\u9762\u51e0\u79cd\u65b9\u6cd5\u53ef\u4ee5\u4e0b\u8f7d\uff1a \u5728 Ubuntu \u673a\u5668\u4e0a\u76f4\u63a5\u4f7f\u7528\u6d4f\u89c8\u5668\u4e0b\u8f7d \u5728\u81ea\u5df1\u673a\u5668\u4e0a\u4e0b\u8f7d\uff0c\u7136\u540e\u901a\u8fc7 scp \u4f20\u5230 Ubuntu \u673a\u5668\u4e0a \u5728\u81ea\u5df1\u673a\u5668\u4e0a\u627e\u5230\u4e0b\u8f7d\u5730\u5740\uff0c\u7136\u540e\u5728 Ubuntu \u673a\u5668\u4e0a\u4f7f\u7528 wget \u547d\u4ee4\u4e0b\u8f7d \u4ee5\u4e0a\u65b9\u6cd5\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u60c5\u51b5\u9009\u62e9\uff0c\u8fd9\u91cc\u6211\u9009\u62e9\u7b2c\u4e09\u79cd\u65b9\u6cd5\uff1a wget https://cn.download.nvidia.cn/XFree86/Linux-x86_64/450.80.02/NVIDIA-Linux-x86_64-450.80.02.run","title":"\u4e0b\u8f7d\u9a71\u52a8"},{"location":"ubuntu-install-guide/#nouveau","text":"\u5982\u679c\u4f60\u6ca1\u6709\u5c4f\u853d\uff0c\u5c31\u4f1a\u51fa\u73b0\u4ee5\u4e0b\u63d0\u793a\uff1a ERROR: The Nouveau kernel driver is currently in use by your system. This driver is incompatible with the NVIDIA driver, and must be disabled before proceeding. Please consult the NVIDIA driver README and your Linux distribution's documentation for details on how to correctly disable the Nouveau kernel driver. \u547d\u4ee4\uff1a sudo nano /etc/modprobe.d/blacklist-nouveau.conf # \u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9 blacklist nouveau options nouveau modeset = 0 # \u4fdd\u5b58 sudo update-initramfs -u sudo reboot","title":"\u5c4f\u853d Nouveau"},{"location":"ubuntu-install-guide/#_7","text":"\u5982\u679c\u6ca1\u6709\u5b89\u88c5 gcc \u7b49\u7f16\u8bd1\u5de5\u5177\uff0c\u5c31\u4f1a\u51fa\u73b0\u4ee5\u4e0b\u63d0\u793a\uff1a ERROR: Unable to find the development tool cc in your path; please make sure that you have the package 'gcc' installed. If gcc is installed on your system, then please check that cc is in your PATH. \u547d\u4ee4\uff1a sudo apt install -y build-essential gcc g++ make binutils linux-headers- ` uname -r `","title":"\u5b89\u88c5\u5fc5\u8981\u7684\u7f16\u8bd1\u5de5\u5177"},{"location":"ubuntu-install-guide/#_8","text":"sudo bash NVIDIA-Linux-x86_64-450.80.02.run \u5b89\u88c5\u6b65\u9aa4\u5f88\u7b80\u5355\uff0c\u4e00\u76f4\u4e0b\u4e00\u6b65\u5c31\u597d\u4e86\u3002","title":"\u5b89\u88c5\u663e\u5361\u9a71\u52a8"},{"location":"ubuntu-install-guide/#_9","text":"nvidia-smi \u5982\u679c\u80fd\u770b\u5230\u7c7b\u4f3c\u7684\u5185\u5bb9\u5c31\u8bf4\u660e\u663e\u5361\u9a71\u52a8\u88c5\u597d\u4e86\uff1a Fri Jan 15 21:15:14 2021 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 GeForce RTX 3080 Off | 00000000:01:00.0 On | N/A | | 31% 22C P8 6W / 320W | 183MiB / 10015MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | 0 N/A N/A 1151 G /usr/lib/xorg/Xorg 142MiB | | 0 N/A N/A 1454 G /usr/bin/gnome-shell 38MiB | +-----------------------------------------------------------------------------+","title":"\u6d4b\u8bd5\u663e\u5361"},{"location":"ubuntu-install-guide/#cuda-cudnn_1","text":"\u7531\u4e8e\u4e0d\u540c\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684 CUDA \u548c cuDNN \u7248\u672c\u4f9d\u8d56\u662f\u4e0d\u540c\u7684\uff0c\u6240\u4ee5\u8bf7\u6309\u7167\u4f60\u6240\u9700\u8981\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u5b98\u7f51\u4e0a\u7684\u8bf4\u660e\u4e3a\u51c6\u3002\u5173\u4e8e CUDA \u7248\u672c\u3001cuDNN\u7248\u672c\u4ee5\u53ca\u6df1\u5ea6\u5b66\u4e60\u73af\u5883\u7684\u4ecb\u7ecd\uff0c\u8bf7\u770b Ubuntu \u73af\u5883 \u3002 \u63d0\u793a\uff1aPyTorch \u7528\u6237\u53ef\u4ee5\u4e0d\u5b89\u88c5 CUDA \u548c cuDNN\u3002","title":"\u5b89\u88c5 CUDA \u548c cuDNN"},{"location":"ubuntu-install-guide/#cuda-100","text":"\u7531\u4e8e\u6b64\u5b89\u88c5\u5305\u6bd4\u8f83\u5927\uff0c\u5efa\u8bae\u4f7f\u7528 aria2c \u4e0b\u8f7d\uff1a aria2c -x 16 https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux \u4e0b\u8f7d\u597d\u4e86\u4ee5\u540e\uff0c\u76f4\u63a5\u8fd0\u884c\u5b89\u88c5\u5373\u53ef\uff1a sudo bash cuda_10.0.130_410.48_linux.run # \u6309 q \u9000\u51fa EULA NVIDIA CUDA Toolkit Do you accept the previously read EULA? accept/decline/quit: accept Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 410 .48? ( y ) es/ ( n ) o/ ( q ) uit: n Install the CUDA 10 .0 Toolkit? ( y ) es/ ( n ) o/ ( q ) uit: y Enter Toolkit Location [ default is /usr/local/cuda-10.0 ] : Do you want to install a symbolic link at /usr/local/cuda? ( y ) es/ ( n ) o/ ( q ) uit: y Install the CUDA 10 .0 Samples? ( y ) es/ ( n ) o/ ( q ) uit: n Installing the CUDA Toolkit in /usr/local/cuda-10.0 ... =========== = Summary = =========== Driver: Not Selected Toolkit: Installed in /usr/local/cuda-10.0 Samples: Not Selected \u53ef\u4ee5\u6309\u7167\u81ea\u5df1\u7684\u9700\u8981\u8bf7\u914d\u7f6e\u4e0b\u9762\u7684\u9009\u9879\uff0c\u6bd4\u5982\u4f60\u60f3\u5b66\u4e60\u4f7f\u7528 C/C++ \u7f16\u5199 CUDA \u7a0b\u5e8f\uff0c\u53ef\u4ee5\u5b89\u88c5 Samples\u3002 \u6ce8\u610f\uff1a Please make sure that PATH includes /usr/local/cuda-10.0/bin LD_LIBRARY_PATH includes /usr/local/cuda-10.0/lib64, or, add /usr/local/cuda-10.0/lib64 to /etc/ld.so.conf and run ldconfig as root \u9700\u8981\u6309\u7167\u4e0a\u9762\u7684\u6307\u793a \u914d\u7f6e\u73af\u5883\u53d8\u91cf \uff0c\u8fd9\u91cc\u6211\u4ee5 ~/.zshrc \u4e3a\u4f8b\uff1a nano ~/.zshrc # \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9 export PATH = /usr/local/cuda/bin: $PATH export LD_LIBRARY_PATH = /usr/local/cuda/lib64: $PATH","title":"\u5b89\u88c5 CUDA 10.0"},{"location":"ubuntu-install-guide/#cudnn","text":"\u540c\u6837\uff0c\u4e0b\u8f7d cudnn-10.0-linux-x64-v7.6.0.64.tgz\uff1a aria2c -x 16 http://developer.download.nvidia.com/compute/redist/cudnn/v7.6.0/cudnn-10.0-linux-x64-v7.6.0.64.tgz \u7136\u540e\u5b89\u88c5\u5230 /usr/local \u76ee\u5f55\u4e0b\uff1a sudo tar -xzf cudnn-10.0-linux-x64-v7.6.0.64.tgz -C /usr/local","title":"\u5b89\u88c5 cuDNN"},{"location":"ubuntu-install-guide/#anaconda-python","text":"","title":"\u5b89\u88c5 Anaconda \u548c Python \u5e93"},{"location":"ubuntu-install-guide/#anaconda","text":"\u5b89\u88c5 Anaconda \u548c Python \u5e93\u7684\u6b65\u9aa4\u90fd\u5df2\u7ecf\u5199\u5728\u4e86 Pyhton \u73af\u5883 \uff0c\u8fd9\u91cc\u4ec5\u4ec5\u5c55\u793a\u76f8\u5173\u547d\u4ee4\uff1a aria2c -x 16 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.03-Linux-x86_64.sh bash Anaconda3-2019.03-Linux-x86_64.sh # \u56de\u8f66\uff0c\u7136\u540e\u6309 q \u9000\u51fa EULA Do you accept the license terms? [ yes | no ] [ no ] >>> yes Anaconda3 will now be installed into this location: /home/ypw/anaconda3 - Press ENTER to confirm the location - Press CTRL-C to abort the installation - Or specify a different location below [ /home/ypw/anaconda3 ] >>> PREFIX = /home/ypw/anaconda3 installing: python-3.7.3-h0371630_0 ... Python 3 .7.3 installing: conda-env-2.6.0-1 ... installing: blas-1.0-mkl ... ...... installing: anaconda-2019.03-py37_0 ... installation finished. Do you wish the installer to initialize Anaconda3 by running conda init? [ yes | no ] [ no ] >>> yes ...... Thank you for installing Anaconda3! \u5b89\u88c5\u5b8c\u6210\u4ee5\u540e\uff0c\u4f60\u53ef\u80fd\u8fd8\u9700\u8981 \u914d\u7f6e\u73af\u5883\u53d8\u91cf \u3002 ~/anaconda3/bin/conda init # \u5982\u679c\u4f60\u7528\u7684\u7ec8\u7aef\u662fzsh ~/anaconda3/bin/conda init zsh \u914d\u7f6e\u597d\u4ee5\u540e\uff0c\u53ef\u4ee5\u91cd\u542f\u673a\u5668\uff0c\u6216\u8005\u4f7f\u7528 source ~/.zshrc \u66f4\u65b0\u73af\u5883\u53d8\u91cf \u3002","title":"\u5b89\u88c5 Anaconda"},{"location":"ubuntu-install-guide/#pip","text":"\u5728\u4f7f\u7528 pip \u7684\u65f6\u5019\u6709\u53ef\u80fd\u56e0\u4e3a\u7f51\u7edc\u539f\u56e0\u5bfc\u81f4\u5b89\u88c5\u8fc7\u6162\u6216\u5931\u8d25\uff0c\u8fd9\u65f6\u5019\u53ef\u4ee5 \u914d\u7f6e\u56fd\u5185\u7684 pip \u6e90 \uff1a https://developer.aliyun.com/mirror/pypi https://mirror.tuna.tsinghua.edu.cn/help/pypi/ \u4e0b\u9762\u4ee5\u963f\u91cc\u4e91\u4e3a\u4f8b\uff1a pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/","title":"\u914d\u7f6e pip \u6e90"},{"location":"ubuntu-install-guide/#python","text":"\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u5b89\u88c5 \u5e38\u7528 Python \u5e93 \uff1a pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx xlrd openpyxl \u6ce8\u610f\uff1a\u5982\u679c\u662f 30 \u7cfb\u5217\u7684\u663e\u5361\uff0c\u6bd4\u5982 3080\u30013090\uff0c\u9700\u8981\u4f7f\u7528CUDA11\u6216\u4ee5\u4e0a\u7684\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\uff0c\u6bd4\u5982 PyTorch \u76ee\u524d\u662f\u8fd9\u6837\u5b89\u88c5\u7684\uff1a pip install torch == 1 .7.1+cu110 torchvision == 0 .8.2+cu110 torchaudio === 0 .7.2 -f https://download.pytorch.org/whl/torch_stable.html","title":"Python \u5e93"},{"location":"ubuntu-install-guide/#pytorch","text":"import torch dummy = torch . zeros ( 1 , 3 , 5 , 5 ) . cuda () conv = torch . nn . Conv2d ( in_channels = 3 , out_channels = 1 , kernel_size = 3 ) . cuda () print ( conv ( dummy )) \u671f\u671b\u8f93\u51fa\uff1a tensor ([[[[ 0.0443 , 0.0443 , 0.0443 ], [ 0.0443 , 0.0443 , 0.0443 ], [ 0.0443 , 0.0443 , 0.0443 ]]]], device = 'cuda:0' , grad_fn =< CudnnConvolutionBackward > )","title":"\u6d4b\u8bd5 PyTorch"},{"location":"ubuntu-install-guide/#tensorflow","text":"import tensorflow as tf mnist = tf.keras.datasets.mnist ( x_train, y_train ) , ( x_test, y_test ) = mnist.load_data () x_train, x_test = x_train / 255 .0, x_test / 255 .0 model = tf.keras.models.Sequential ([ tf.keras.layers.Flatten ( input_shape =( 28 , 28 )) , tf.keras.layers.Dense ( 512 , activation = tf.nn.relu ) , tf.keras.layers.Dropout ( 0 .2 ) , tf.keras.layers.Dense ( 10 , activation = tf.nn.softmax ) ]) model.compile ( optimizer = 'adam' , loss = 'sparse_categorical_crossentropy' , metrics =[ 'accuracy' ]) model.fit ( x_train, y_train, epochs = 5 ) model.evaluate ( x_test, y_test ) \u671f\u671b\u8f93\u51fa\uff08\u6ce8\u610f\u91cc\u9762\u7684 GeForce GTX 1080 Ti\uff09 \uff1a >>> model.fit(x_train, y_train, epochs=5) 2019-07-21 17:18:16.455944: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA 2019-07-21 17:18:16.460577: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3599995000 Hz 2019-07-21 17:18:16.461013: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e83e4f40 executing computations on platform Host. Devices: 2019-07-21 17:18:16.461032: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): , 2019-07-21 17:18:16.462663: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcuda.so.1 2019-07-21 17:18:16.915819: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.916435: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e78c9a40 executing computations on platform CUDA. Devices: 2019-07-21 17:18:16.916504: I tensorflow/compiler/xla/service/service.cc:175] StreamExecutor device (0): GeForce GTX 1080 Ti, Compute Capability 6.1 2019-07-21 17:18:16.916782: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.918218: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties: name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.683 pciBusID: 0000:0b:00.0 2019-07-21 17:18:16.918581: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0 2019-07-21 17:18:16.920971: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0 2019-07-21 17:18:16.922961: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcufft.so.10.0 2019-07-21 17:18:16.923461: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcurand.so.10.0 2019-07-21 17:18:16.926265: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusolver.so.10.0 2019-07-21 17:18:16.928450: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusparse.so.10.0 2019-07-21 17:18:16.932250: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudnn.so.7 2019-07-21 17:18:16.932341: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.932899: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.933392: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0 2019-07-21 17:18:16.933426: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0 2019-07-21 17:18:16.934335: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix: 2019-07-21 17:18:16.934353: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1187] 0 2019-07-21 17:18:16.934363: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1200] 0: N 2019-07-21 17:18:16.934444: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.934988: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero 2019-07-21 17:18:16.935504: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 10481 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:0b:00.0, compute capability: 6.1) Epoch 1/5 2019-07-21 17:18:17.663035: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0 60000/60000 [==============================] - 3s 49us/sample - loss: 0.2209 - acc: 0.9344 Epoch 2/5import torch x = torch.rand(5, 3) print(x) 60000/60000 [==============================] - 2s 39us/sample - loss: 0.0968 - acc: 0.9707 Epoch 3/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0696 - acc: 0.9779 Epoch 4/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0537 - acc: 0.9826 Epoch 5/5 60000/60000 [==============================] - 2s 38us/sample - loss: 0.0428 - acc: 0.9863 >>> model.evaluate(x_test, y_test) 10000/10000 [==============================] - 0s 24us/sample - loss: 0.0698 - acc: 0.9804 [0.06983174340333789, 0.9804]","title":"\u6d4b\u8bd5 TensorFlow"},{"location":"windows-linux-or-macos/","text":"Windows\u3001Ubuntu \u8fd8\u662f macOS\uff1f Windows\u3001Ubuntu \u548c macOS \u8fd9\u4e09\u4e2a\u64cd\u4f5c\u7cfb\u7edf\u90fd\u6709\u4e0d\u53ef\u66ff\u4ee3\u4e4b\u5904\uff0c\u6211\u5728\u5de5\u4f5c\u4e2d\u5927\u90e8\u5206\u60c5\u51b5\u4e0b\u90fd\u4f1a\u4f7f\u7528 macOS \u4f5c\u4e3a\u7ec8\u7aef\uff0c\u5728\u4f7f\u7528 office \u8f6f\u4ef6\u3001\u767e\u5ea6\u4e91\u7684\u65f6\u5019\u4f1a\u7528\u5230 Windows\u3002\u867d\u7136\u6211\u76f4\u63a5\u4f7f\u7528\u7684\u673a\u5668\u662f macOS \u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u4f46\u662f\u5b9e\u9645\u4e0a\u8fd0\u884c\u7a0b\u5e8f\u7684\u673a\u5668\u662f Ubuntu\uff08Linux\uff09\u64cd\u4f5c\u7cfb\u7edf\u3002 Ubuntu \u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6765\u8bf4\uff0cUbuntu \u90fd\u5e94\u8be5\u662f\u9996\u9009\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u6613\u7528\u6027\u5f3a \u4f7f\u7528\u4eba\u6570\u591a\uff0c\u6559\u7a0b\u591a\uff0c\u751f\u6001\u597d \u5404\u4e2a\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u5b98\u65b9\u652f\u6301\uff0c\u6bd4\u5982 PyTorch \u76f4\u5230 2022 \u5e74\u90fd\u6ca1\u6709\u652f\u6301 NCCL \u591a\u5361\u8bad\u7ec3 \u4ece\u5f00\u53d1\u73af\u5883\u5230\u90e8\u7f72\u73af\u5883\uff0cLinux \u7cfb\u7edf\u8d2f\u7a7f\u59cb\u7ec8\uff0c\u9009\u62e9\u4e00\u6b3e\u6613\u7528\u7684 Linux \u64cd\u4f5c\u7cfb\u7edf\u5c06\u4f1a\u7f29\u77ed\u5f00\u53d1\u5468\u671f\u3002 macOS \u4f7f\u7528 macOS \u7684\u539f\u56e0\u6709\u5f88\u591a\uff0c\u4e0b\u9762\u6211\u4eec\u9010\u4e00\u5206\u6790\u3002 \u4ece\u786c\u4ef6\u4e0a\u6765\u8bf4\uff1a \u7f8e\u89c2\uff0c\u82f9\u679c\u7684\u5de5\u4e1a\u8bbe\u8ba1\u662f\u975e\u5e38\u68d2\u7684 \u6d41\u7545\uff0c\u89e6\u63a7\u677f\u7684\u6eda\u52a8\u548c\u7f29\u653e\u6548\u679c\u8212\u9002 \u89c6\u7f51\u819c\u663e\u793a\u5c4f\uff0c\u5206\u8fa8\u7387\u6781\u9ad8\uff0c\u9ad8\u5e27\u6570\u6d41\u7545\uff0c\u9ad8\u989c\u8272\u7684\u8fd8\u539f\u4ee5\u53ca\u4eae\u5ea6\u548c\u8272\u6e29\u7684\u63a7\u5236\u90fd\u5f88\u6070\u5f53 \u7eed\u822a\u65f6\u95f4\u957f \u8010\u7528\uff0c\u4e00\u53f0\u82f9\u679c\u7535\u8111\u7528\u56db\u4e94\u5e74\u90fd\u548c\u521a\u4e70\u6765\u4e00\u6837 iMac 5K \u62e5\u670927\u5bf8\u7684\u5c4f\u5e55\uff0c\u53ef\u4ee5\u540c\u65f6\u663e\u793a\u591a\u4e2a\u7a97\u53e3\u548c\u7ec8\u7aef \u4ece\u8f6f\u4ef6\u4e0a\u6765\u8bf4\uff1a \u7f8e\u89c2\uff0c\u4ece\u7cfb\u7edf UI \u4e0a\u6765\u8bf4\uff0c\u82f9\u679c\u7684\u5ba1\u7f8e\u662f\u6709\u4fdd\u969c\u7684\uff0c\u751a\u81f3\u5728 macOS \u4e0a\u5f00\u53d1\u7684\u8f6f\u4ef6\u90fd\u4f1a\u6ce8\u91cd\u5ba1\u7f8e \u73af\u5883\u4e0e Linux \u63a5\u8fd1\uff0c\u7ec8\u7aef\u547d\u4ee4\u57fa\u672c\u662f\u901a\u7528\u7684\uff0c\u5728\u4f7f\u7528\u4e0a\u65e0\u7f1d\u5207\u6362 \u66f4\u5b89\u5168\uff0c\u5168\u76d8\u52a0\u5bc6\uff0c\u4e0d\u7528\u62c5\u5fc3\u88ab\u5077\u4ee5\u540e\u88ab\u7a83\u53d6\u6587\u4ef6\uff0c\u5e76\u4e14\u7531\u4e8e\u5360\u6709\u7387\u4f4e\uff0c\u5c11\u6709\u4e3a macOS \u5f00\u53d1\u7684\u75c5\u6bd2\u8f6f\u4ef6 \u4e0e\u5176\u4ed6\u82f9\u679c\u8bbe\u5907\u5408\u4f5c\u5f88\u7d27\u5bc6\uff0c\u6bd4\u5982\u684c\u9762\u7684\u6587\u4ef6\u53ef\u4ee5\u5728\u6bcf\u53f0\u8bbe\u5907\u4e0a\u540c\u6b65\uff0c\u751a\u81f3\u53ef\u4ee5\u76f4\u63a5\u5728 iPhone \u4e0a\u67e5\u770b \u6709\u4eba\u53ef\u80fd\u8003\u8651\u4f7f\u7528 macOS \u5916\u63a5 NVIDIA \u663e\u5361\u8dd1\u6df1\u5ea6\u5b66\u4e60\uff0c\u8fd9\u91cc\u4e0d\u5efa\u8bae\u8fd9\u6837\u505a\u3002\u56e0\u4e3a\u622a\u6b62\u5230 2019\u5e74 5 \u670815\u65e5\uff0c \u82f1\u4f1f\u8fbe\u9a71\u52a8 \u53ea\u652f\u6301 2018\u5e74 7 \u6708 9 \u65e5\u53d1\u5e03\u7684 macOS High Sierra 10.13.6 \uff0c\u6240\u4ee5\u6211\u4eec\u65e0\u6cd5\u7528\u4e0a\u6700\u65b0\u7248\u672c\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u5b98\u65b9\u8868\u793a \u76ee\u524d\u4e0d\u652f\u6301\u5728 macOS 10.14 \u4e0a\u8fd0\u884c CUDA \uff0c\u82f9\u679c\u4e5f\u8868\u793a\u5916\u63a5\u663e\u5361 \u53ea\u652f\u6301 AMD \u663e\u5361 \u3002 Windows \u8fd9\u4e2a\u64cd\u4f5c\u7cfb\u7edf\u901a\u5e38\u662f\u5927\u5bb6\u6700\u4e3a\u719f\u6089\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u6240\u4ee5\u8fd9\u91cc\u5c31\u4e0d\u518d\u4ecb\u7ecd\u5b83\u7684\u4f18\u70b9\uff0c\u8fd9\u91cc\u53ea\u63d0\u51e0\u4e2a\u7f3a\u70b9\uff1a \u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u5b98\u65b9\u652f\u6301\u4e0d\u591f\u53ca\u65f6\uff0cTensorFlow \u4e8e 2015\u5e7411\u6708\u53d1\u5e03\uff0c\u4f46\u662f\u4e00\u5e74\u4e4b\u540e\u624d\u9996\u6b21\u652f\u6301 Windows\uff1a TensorFlow now builds and runs on Microsoft Windows \u5176\u4ed6\u5b66\u8005\u5f00\u53d1\u7684\u65b0\u6a21\u578b\u7684\u4ee3\u7801\u901a\u5e38\u9700\u8981\u8fdb\u884c\u4fee\u6539\u624d\u80fd\u5728 Windows \u4e0a\u8fd0\u884c\uff0c\u5982\u679c\u4ed6\u4eec\u7684\u4ee3\u7801\u6d89\u53ca CUDA \u7f16\u7a0b\uff0c\u81ea\u5b9a\u4e49\u7b97\u5b50\uff0c\u8fd9\u79cd\u4fee\u6539\u4f1a\u5f88\u56f0\u96be \u8def\u5f84\u7684\u659c\u6760\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0cWindows \u4f7f\u7528\u7684\u662f \\ \uff0c\u5bb9\u6613\u4f5c\u4e3a\u8f6c\u4e49\u5b57\u7b26\u89e3\u6790\u6210\u5176\u4ed6\u5b57\u7b26\u5bfc\u81f4 bug \u6362\u884c\u7b26\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0cWindows \u4f7f\u7528\u7684\u4e0d\u662f \\n \uff0c\u800c\u662f \\r\\n \u547d\u4ee4\u884c\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0c\u8bb8\u591a\u547d\u4ee4\u529f\u80fd\u4e00\u6837\uff0c\u4f46\u662f\u540d\u5b57\u4e0d\u540c\uff0c\u6bd4\u5982 ifconfig \u4e0e ipconfig\uff0crm \u4e0e del \u7b49 \u4e3a\u4e86\u80fd\u591f\u4f7f\u7528\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u5f00\u6e90\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u5efa\u8bae\u4f7f\u7528 Ubuntu \u4f5c\u4e3a\u8fd0\u884c\u4ee3\u7801\u7684\u673a\u5668\u3002","title":"Windows\u3001Ubuntu \u8fd8\u662f macOS\uff1f"},{"location":"windows-linux-or-macos/#windowsubuntu-macos","text":"Windows\u3001Ubuntu \u548c macOS \u8fd9\u4e09\u4e2a\u64cd\u4f5c\u7cfb\u7edf\u90fd\u6709\u4e0d\u53ef\u66ff\u4ee3\u4e4b\u5904\uff0c\u6211\u5728\u5de5\u4f5c\u4e2d\u5927\u90e8\u5206\u60c5\u51b5\u4e0b\u90fd\u4f1a\u4f7f\u7528 macOS \u4f5c\u4e3a\u7ec8\u7aef\uff0c\u5728\u4f7f\u7528 office \u8f6f\u4ef6\u3001\u767e\u5ea6\u4e91\u7684\u65f6\u5019\u4f1a\u7528\u5230 Windows\u3002\u867d\u7136\u6211\u76f4\u63a5\u4f7f\u7528\u7684\u673a\u5668\u662f macOS \u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u4f46\u662f\u5b9e\u9645\u4e0a\u8fd0\u884c\u7a0b\u5e8f\u7684\u673a\u5668\u662f Ubuntu\uff08Linux\uff09\u64cd\u4f5c\u7cfb\u7edf\u3002","title":"Windows\u3001Ubuntu \u8fd8\u662f macOS\uff1f"},{"location":"windows-linux-or-macos/#ubuntu","text":"\u5bf9\u4e8e\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u6765\u8bf4\uff0cUbuntu \u90fd\u5e94\u8be5\u662f\u9996\u9009\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u6613\u7528\u6027\u5f3a \u4f7f\u7528\u4eba\u6570\u591a\uff0c\u6559\u7a0b\u591a\uff0c\u751f\u6001\u597d \u5404\u4e2a\u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u5b98\u65b9\u652f\u6301\uff0c\u6bd4\u5982 PyTorch \u76f4\u5230 2022 \u5e74\u90fd\u6ca1\u6709\u652f\u6301 NCCL \u591a\u5361\u8bad\u7ec3 \u4ece\u5f00\u53d1\u73af\u5883\u5230\u90e8\u7f72\u73af\u5883\uff0cLinux \u7cfb\u7edf\u8d2f\u7a7f\u59cb\u7ec8\uff0c\u9009\u62e9\u4e00\u6b3e\u6613\u7528\u7684 Linux \u64cd\u4f5c\u7cfb\u7edf\u5c06\u4f1a\u7f29\u77ed\u5f00\u53d1\u5468\u671f\u3002","title":"Ubuntu"},{"location":"windows-linux-or-macos/#macos","text":"\u4f7f\u7528 macOS \u7684\u539f\u56e0\u6709\u5f88\u591a\uff0c\u4e0b\u9762\u6211\u4eec\u9010\u4e00\u5206\u6790\u3002 \u4ece\u786c\u4ef6\u4e0a\u6765\u8bf4\uff1a \u7f8e\u89c2\uff0c\u82f9\u679c\u7684\u5de5\u4e1a\u8bbe\u8ba1\u662f\u975e\u5e38\u68d2\u7684 \u6d41\u7545\uff0c\u89e6\u63a7\u677f\u7684\u6eda\u52a8\u548c\u7f29\u653e\u6548\u679c\u8212\u9002 \u89c6\u7f51\u819c\u663e\u793a\u5c4f\uff0c\u5206\u8fa8\u7387\u6781\u9ad8\uff0c\u9ad8\u5e27\u6570\u6d41\u7545\uff0c\u9ad8\u989c\u8272\u7684\u8fd8\u539f\u4ee5\u53ca\u4eae\u5ea6\u548c\u8272\u6e29\u7684\u63a7\u5236\u90fd\u5f88\u6070\u5f53 \u7eed\u822a\u65f6\u95f4\u957f \u8010\u7528\uff0c\u4e00\u53f0\u82f9\u679c\u7535\u8111\u7528\u56db\u4e94\u5e74\u90fd\u548c\u521a\u4e70\u6765\u4e00\u6837 iMac 5K \u62e5\u670927\u5bf8\u7684\u5c4f\u5e55\uff0c\u53ef\u4ee5\u540c\u65f6\u663e\u793a\u591a\u4e2a\u7a97\u53e3\u548c\u7ec8\u7aef \u4ece\u8f6f\u4ef6\u4e0a\u6765\u8bf4\uff1a \u7f8e\u89c2\uff0c\u4ece\u7cfb\u7edf UI \u4e0a\u6765\u8bf4\uff0c\u82f9\u679c\u7684\u5ba1\u7f8e\u662f\u6709\u4fdd\u969c\u7684\uff0c\u751a\u81f3\u5728 macOS \u4e0a\u5f00\u53d1\u7684\u8f6f\u4ef6\u90fd\u4f1a\u6ce8\u91cd\u5ba1\u7f8e \u73af\u5883\u4e0e Linux \u63a5\u8fd1\uff0c\u7ec8\u7aef\u547d\u4ee4\u57fa\u672c\u662f\u901a\u7528\u7684\uff0c\u5728\u4f7f\u7528\u4e0a\u65e0\u7f1d\u5207\u6362 \u66f4\u5b89\u5168\uff0c\u5168\u76d8\u52a0\u5bc6\uff0c\u4e0d\u7528\u62c5\u5fc3\u88ab\u5077\u4ee5\u540e\u88ab\u7a83\u53d6\u6587\u4ef6\uff0c\u5e76\u4e14\u7531\u4e8e\u5360\u6709\u7387\u4f4e\uff0c\u5c11\u6709\u4e3a macOS \u5f00\u53d1\u7684\u75c5\u6bd2\u8f6f\u4ef6 \u4e0e\u5176\u4ed6\u82f9\u679c\u8bbe\u5907\u5408\u4f5c\u5f88\u7d27\u5bc6\uff0c\u6bd4\u5982\u684c\u9762\u7684\u6587\u4ef6\u53ef\u4ee5\u5728\u6bcf\u53f0\u8bbe\u5907\u4e0a\u540c\u6b65\uff0c\u751a\u81f3\u53ef\u4ee5\u76f4\u63a5\u5728 iPhone \u4e0a\u67e5\u770b \u6709\u4eba\u53ef\u80fd\u8003\u8651\u4f7f\u7528 macOS \u5916\u63a5 NVIDIA \u663e\u5361\u8dd1\u6df1\u5ea6\u5b66\u4e60\uff0c\u8fd9\u91cc\u4e0d\u5efa\u8bae\u8fd9\u6837\u505a\u3002\u56e0\u4e3a\u622a\u6b62\u5230 2019\u5e74 5 \u670815\u65e5\uff0c \u82f1\u4f1f\u8fbe\u9a71\u52a8 \u53ea\u652f\u6301 2018\u5e74 7 \u6708 9 \u65e5\u53d1\u5e03\u7684 macOS High Sierra 10.13.6 \uff0c\u6240\u4ee5\u6211\u4eec\u65e0\u6cd5\u7528\u4e0a\u6700\u65b0\u7248\u672c\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u5b98\u65b9\u8868\u793a \u76ee\u524d\u4e0d\u652f\u6301\u5728 macOS 10.14 \u4e0a\u8fd0\u884c CUDA \uff0c\u82f9\u679c\u4e5f\u8868\u793a\u5916\u63a5\u663e\u5361 \u53ea\u652f\u6301 AMD \u663e\u5361 \u3002","title":"macOS"},{"location":"windows-linux-or-macos/#windows","text":"\u8fd9\u4e2a\u64cd\u4f5c\u7cfb\u7edf\u901a\u5e38\u662f\u5927\u5bb6\u6700\u4e3a\u719f\u6089\u7684\u64cd\u4f5c\u7cfb\u7edf\uff0c\u6240\u4ee5\u8fd9\u91cc\u5c31\u4e0d\u518d\u4ecb\u7ecd\u5b83\u7684\u4f18\u70b9\uff0c\u8fd9\u91cc\u53ea\u63d0\u51e0\u4e2a\u7f3a\u70b9\uff1a \u6df1\u5ea6\u5b66\u4e60\u6846\u67b6\u7684\u5b98\u65b9\u652f\u6301\u4e0d\u591f\u53ca\u65f6\uff0cTensorFlow \u4e8e 2015\u5e7411\u6708\u53d1\u5e03\uff0c\u4f46\u662f\u4e00\u5e74\u4e4b\u540e\u624d\u9996\u6b21\u652f\u6301 Windows\uff1a TensorFlow now builds and runs on Microsoft Windows \u5176\u4ed6\u5b66\u8005\u5f00\u53d1\u7684\u65b0\u6a21\u578b\u7684\u4ee3\u7801\u901a\u5e38\u9700\u8981\u8fdb\u884c\u4fee\u6539\u624d\u80fd\u5728 Windows \u4e0a\u8fd0\u884c\uff0c\u5982\u679c\u4ed6\u4eec\u7684\u4ee3\u7801\u6d89\u53ca CUDA \u7f16\u7a0b\uff0c\u81ea\u5b9a\u4e49\u7b97\u5b50\uff0c\u8fd9\u79cd\u4fee\u6539\u4f1a\u5f88\u56f0\u96be \u8def\u5f84\u7684\u659c\u6760\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0cWindows \u4f7f\u7528\u7684\u662f \\ \uff0c\u5bb9\u6613\u4f5c\u4e3a\u8f6c\u4e49\u5b57\u7b26\u89e3\u6790\u6210\u5176\u4ed6\u5b57\u7b26\u5bfc\u81f4 bug \u6362\u884c\u7b26\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0cWindows \u4f7f\u7528\u7684\u4e0d\u662f \\n \uff0c\u800c\u662f \\r\\n \u547d\u4ee4\u884c\u4e0e\u5176\u4ed6\u64cd\u4f5c\u7cfb\u7edf\u4e0d\u540c\uff0c\u8bb8\u591a\u547d\u4ee4\u529f\u80fd\u4e00\u6837\uff0c\u4f46\u662f\u540d\u5b57\u4e0d\u540c\uff0c\u6bd4\u5982 ifconfig \u4e0e ipconfig\uff0crm \u4e0e del \u7b49 \u4e3a\u4e86\u80fd\u591f\u4f7f\u7528\u5927\u591a\u6570\u6df1\u5ea6\u5b66\u4e60\u5de5\u7a0b\u5e08\u5f00\u6e90\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u5efa\u8bae\u4f7f\u7528 Ubuntu \u4f5c\u4e3a\u8fd0\u884c\u4ee3\u7801\u7684\u673a\u5668\u3002","title":"Windows"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..80139fa --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,93 @@ + + + + https://dl.ypw.io/ + 2023-12-13 + daily + + + https://dl.ypw.io/best-models-on-imagenet/ + 2023-12-13 + daily + + + https://dl.ypw.io/cv-dataset/ + 2023-12-13 + daily + + + https://dl.ypw.io/cv-resources/ + 2023-12-13 + daily + + + https://dl.ypw.io/detection-models/ + 2023-12-13 + daily + + + https://dl.ypw.io/docker-is-good/ + 2023-12-13 + daily + + + https://dl.ypw.io/how-to-build-deep-learning-workstation/ + 2023-12-13 + daily + + + https://dl.ypw.io/how-to-use-tensorboard/ + 2023-12-13 + daily + + + https://dl.ypw.io/linux-command/ + 2023-12-13 + daily + + + https://dl.ypw.io/mac-compare/ + 2023-12-13 + daily + + + https://dl.ypw.io/macos-environment/ + 2023-12-13 + daily + + + https://dl.ypw.io/macos-software/ + 2023-12-13 + daily + + + https://dl.ypw.io/offline-python-environment/ + 2023-12-13 + daily + + + https://dl.ypw.io/python-environment/ + 2023-12-13 + daily + + + https://dl.ypw.io/remote-debugging-with-pycharm/ + 2023-12-13 + daily + + + https://dl.ypw.io/ubuntu-environment/ + 2023-12-13 + daily + + + https://dl.ypw.io/ubuntu-install-guide/ + 2023-12-13 + daily + + + https://dl.ypw.io/windows-linux-or-macos/ + 2023-12-13 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..44c0e9e Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/ubuntu-environment/index.html b/ubuntu-environment/index.html new file mode 100644 index 0000000..5a46903 --- /dev/null +++ b/ubuntu-environment/index.html @@ -0,0 +1,2135 @@ + + + + + + + + + + + + + + + + + + + + + + + Ubuntu 环境 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    Ubuntu 环境

    +

    CUDA

    + +

    CUDA 是英伟达显卡进行各种高性能运算必备的库,不同软件包依赖的 CUDA 版本可能不同,你需要根据你所使用的深度学习框架选择合适的 CUDA 和 cuDNN 版本。

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    版本Windows 10Linux
    CUDA 11.3cuda_11.3.1_465.89_win10.execuda_11.3.1_465.19.01_linux.run
    CUDA 10.2cuda_10.2.89_441.22_win10.execuda_10.2.89_440.33.01_linux.run
    CUDA 10.1cuda_10.1.243_426.00_win10.execuda_10.1.243_418.87.00_linux.run
    CUDA 10.0cuda_10.0.130_411.31_win10.execuda_10.0.130_410.48_linux.run
    以下版本较低,推荐使用上面的版本。
    CUDA 9.2cuda_9.2.148_win10.execuda_9.2.148_396.37_linux.run
    CUDA 9.1cuda_9.1.85_win10.execuda_9.1.85_387.26_linux.run
    CUDA 9.0cuda_9.0.176_win10.execuda_9.0.176_384.81_linux.run
    CUDA 8.0 GA2cuda_8.0.61_win10.execuda_8.0.61_375.26_linux.run
    CUDA 8.0 GA1cuda_8.0.44_win10.execuda_8.0.44_linux.run
    CUDA 7.5cuda_7.5.18_win10.execuda_7.5.18_linux.run
    CUDA 7.0cuda_7.0.28_windows.execuda_7.0.28_linux.run
    CUDA 6.5cuda_6.5.14_windows_general_64.execuda_6.5.14_linux_64.run
    +

    cuDNN

    +

    cuDNN 下载需要注册,地址如下:

    + +

    cuDNN 是英伟达推出的专门用于深度学习加速计算的库,一般深度学习框架会使用 cuDNN。

    +

    你需要根据你所使用的深度学习框架选择合适的 CUDA 和 cuDNN 版本。

    +

    下表是常见版本的 cuDNN Linux 下载链接:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    cuDNNCUDA9.0CUDA10.0CUDA10.2CUDA11.2CUDA11.3
    8.2.1--cudnn-10.2-linux-x64-v8.2.1.32.tgz (959.98MB)-cudnn-11.3-linux-x64-v8.2.1.32.tgz (1.75GB)
    8.1.0--cudnn-10.2-linux-x64-v8.1.0.77.tgz (720.54MB)cudnn-11.2-linux-x64-v8.1.0.77.tgz (1.23GB)-
    7.4.1cudnn-9.0-linux-x64-v7.4.1.5.tgz (347.17MB)cudnn-10.0-linux-x64-v7.4.1.5.tgz (403.12MB)---
    7.2.1cudnn-9.0-linux-x64-v7.2.1.38.tgz (331.19MB)----
    7.1.4cudnn-9.0-linux-x64-v7.1.tgz (390.26MB)----
    +

    下表是常见版本的 cuDNN Windows 下载链接:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    cuDNNCUDA9.0CUDA10.0CUDA10.2CUDA11.2CUDA11.3
    8.2.1--cudnn-10.2-windows10-x64-v8.2.1.32.zip (392.82MB)--
    8.1.0--cudnn-10.2-windows10-x64-v8.1.0.77.zip (358.77MB)--
    7.4.1cudnn-9.0-windows10-x64-v7.4.1.5.zip (179.09MB)cudnn-10.0-windows10-x64-v7.4.1.5.zip (208.93MB)---
    7.2.1cudnn-9.0-windows10-x64-v7.2.1.38.zip (171.64MB)----
    7.1.4cudnn-9.0-windows10-x64-v7.1.zip (201.39MB)----
    +

    TensorRT

    +

    TensorRT 是英伟达推出的推断库(Inference),通常用于模型部署。

    +

    使用 TensorRT 可以进行半精度推断,甚至对模型进行 int8 量化,从而得到数倍的性能提升,并且尽可能保证精度。由于此项目还在开发阶段,不同的版本可能不通用,请参考你所使用的深度学习框架的文档,找到你所需要安装的 TensorRT 版本。

    +

    TensorFlow

    +

    安装教程:https://www.tensorflow.org/install/gpu

    +

    最新版的 TensorFlow 1.14.0 依赖 CUDA 10.0,并且 cuDNN 需要 7.4.1 或更高的版本,NVIDIA 驱动需要 410.x 或更高版本。

    +

    历史版本依赖环境

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TensorFlowCUDAcuDNNNVIDIA DriverNCCLTensorRT
    1.1410.07.4.14102.25.0
    1.1310.07.4.14102.25.0
    1.129.07.23842.24.0
    1.119.07.23842.24.0
    1.109.07.13842.24.0
    1.99.07.03.0
    1.89.07.03.0
    1.79.07.03.0
    1.69.07.0
    1.59.07.0
    1.48.06.0
    1.38.06.0
    1.28.05.1
    1.18.05.1
    1.08.05.1
    +

    提示:

    +
      +
    • NVIDIA Driver 为空,官方文档说的是只要安装满足 CUDA 版本的驱动即可
    • +
    • NCCL 和 TensorRT 为空,表示不需要安装
    • +
    +

    PyTorch

    +

    PyTorch 自带 CUDA 和 cuDNN,只需要安装 NVIDIA 驱动即可运行。

    +

    目前 PyPI 安装的 PyTorch 使用的是 CUDA9.0,如果你需要其他版本,请使用官网上的选择器找到你需要的版本,比如 Python 3.7 安装 CUDA10 的 PyTorch 需要使用下面的命令:

    +
    pip3 install https://download.pytorch.org/whl/cu100/torch-1.1.0-cp37-cp37m-linux_x86_64.whl
    +pip3 install https://download.pytorch.org/whl/cu100/torchvision-0.3.0-cp37-cp37m-linux_x86_64.whl
    +
    + +

    必备命令

    +
    sudo apt install -y git curl htop nload tmux screen aria2 graphviz aptitude tree iotop
    +
    + +

    常见的 git、htop、nload 等命令在 macOS 环境 里已经介绍过了。其实大部分命令在没有安装的时候,如果你使用它们,会自动提示需要安装,所以不用担心没有安装全:

    +
    ypw@ypw-ubuntu:~$ screen
    +
    +Command 'screen' not found, but can be installed with:
    +
    +sudo apt install screen
    +
    + +

    curl

    +

    curl 是一个多功能的网络操作命令,你可以使用它来发送 GET、POST 请求。

    +

    在开发服务的时候,我们会经常使用这个命令来测试服务是否能返回预期的结果。

    +

    GET:

    +
    curl https://dl.ypw.io
    +
    + +

    POST:

    +
    curl -d "param1=value1&param2=value2" -X POST http://localhost:3000/data
    +
    + +

    POST json:

    +
    curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:3000/data
    +
    + +

    tmux

    +

    tmux 最大的好处是可以让你的命令在后台运行,不会因为终端关闭而退出。比如在后台运行 jupyter、python 数据预处理脚本和训练脚本等。

    +

    tmux 是一个优秀的终端复用器命令,用户可以通过tmux 在一个终端内管理多个分离的会话,窗口及面板,对于同时使用多个命令行,或多个任务时非常方便。

    +

    创建会话

    +

    比如你想同时监控 CPU、内存、显卡使用情况,那么你可以在使用 iTerm2 的情况下,执行下面的命令开启一个 tmux 会话(session):

    +
    tmux -CC new -s monitor
    +
    + +

    其中的 monitor 是这个会话的名字,你可以修改为自己喜欢的名字。

    +

    修改布局

    +

    在弹出的窗口(window)中,你可以:

    +
      +
    • 使用 ⌘+D Command + D 横向分割这个窗口
    • +
    • 使用 ⌘+⇧+D Command + Shift + D 纵向分割这个窗口
    • +
    • 使用 ⌘+N Command + N 创建一个新的窗口
    • +
    +

    当你调整好布局以后,可以在每个窗格(panel)里运行你想运行的命令。

    +

    窗口大小可以使用鼠标进行调整,窗格大小也可以使用鼠标拖动修改。

    +

    修改好以后,我们可以得到类似下图的效果:

    +

    tmux

    +

    脱离会话

    +

    如果你想让 python 脚本在后台运行,只需要在刚才创建会话的地方按一下 esc 键,就可以脱离这个会话。

    +
    ➜  ~ tmux -CC new -s monitor
    +** tmux mode started **
    +
    +Command Menu
    +----------------------------
    +esc    Detach cleanly.
    +  X    Force-quit tmux mode.
    +  L    Toggle logging.
    +  C    Run tmux command.
    +
    + +

    你也可以直接关闭开启会话的终端的窗口,效果一样。

    +

    恢复会话

    +

    恢复会话可以使用这个命令:tmux -CC attach -t monitor

    +

    退出会话

    +

    如果你想完全退出所有的终端,只需要在每个窗格里 ⌘+W Command + W 即可,关闭最后一个窗口以后,这个会话就结束了。

    +

    screen

    +

    screen 和 tmux 一样都是在后台运行命令的工具。

    +

    新建窗口

    +
    screen -S jupyter
    +
    + +

    其中 -S 后面跟的是 screen 的名字。

    +

    恢复窗口

    +
    screen -r jupyter
    +
    + +

    其中 -r 后面跟的是 screen 的名字。

    +

    退出窗口

    +

    你可以在窗口中使用 exit 命令退出窗口,也可以使用下面的命令:

    +
    screen -X -S jupyter quit
    +
    + +

    其中 -S 后面跟的是 screen 的名字。

    +

    在 screen 里支持滚轮

    +

    新建一个 ~/.screenrc 文件,在里面添加一行 termcapinfo xterm* ti@:te@ 并保存,重新连接 screen 就可以使用滚轮了。

    +

    进入拷贝模式

    +

    输入快捷键 Ctrl + a + [ 进入拷贝模式,然后你就可以使用方向键、翻页键进行翻页。

    +

    下面是拷贝模式下的常用快捷键:

    +
    h -    Move the cursor left by one character
    +j -    Move the cursor down by one line
    +k -    Move the cursor up by one line
    +l -    Move the cursor right by one character
    +0 -    Move to the beginning of the current line
    +$ -    Move to the end of the current line.
    +G -    Moves to the specified line
    +       (defaults to the end of the buffer).
    +C-u -  Scrolls a half page up.
    +C-b -  Scrolls a full page up.
    +C-d -  Scrolls a half page down.
    +C-f -  Scrolls the full page down.
    +
    + +

    如果你记不得这么多快捷键,推荐 iTerm2 + tmux 的组合。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ubuntu-install-guide/index.html b/ubuntu-install-guide/index.html new file mode 100644 index 0000000..8aa83d8 --- /dev/null +++ b/ubuntu-install-guide/index.html @@ -0,0 +1,1732 @@ + + + + + + + + + + + + + + + + + + + + + + + Ubuntu 装机步骤 - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    Ubuntu 装机步骤

    +
      +
    • 安装 Ubuntu
    • +
    • 配置 ssh
    • +
    • 配置 sudo 免密码 和 apt 源(推荐)
    • +
    • 安装 oh my zsh 以及常用命令(推荐)
    • +
    • 安装 NVIDIA 驱动、CUDA 和 cuDNN(分为 apt 和 run 两种安装方式)
    • +
    • 安装 Anaconda 和 Python 库
    • +
    +

    脚本式装机

    +

    Ubuntu 22.04 以前:

    +
    # 添加 sudo 免密码
    +if [[ $(sudo grep -L $USER /etc/sudoers) ]]; then
    +  echo "Add $USER to sudoers"
    +  echo "$USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers;
    +fi
    +
    + +

    Ubuntu 22.04 及以后:

    +
    FILE="/etc/sudoers.d/$USER"
    +if [ ! -f "$FILE" ]; then
    +    echo "Create $FILE and add sudo permission"
    +    echo "$USER ALL=(ALL) NOPASSWD:ALL" | sudo tee "$FILE"
    +fi
    +
    + +
    +
    # 升级系统
    +sudo apt update
    +sudo apt upgrade -y
    +
    + +
    # 安装常用命令和 oh-my-zsh
    +sudo apt install -y openssh-server git curl zsh net-tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop cifs-utils landscape-common p7zip-full
    +sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
    +
    + +
    # 安装 Python 环境
    +wget https://mirrors.bfsu.edu.cn/anaconda/miniconda/Miniconda3-py310_23.3.1-0-Linux-x86_64.sh
    +bash Miniconda3-py310_23.3.1-0-Linux-x86_64.sh -b
    +~/miniconda3/bin/conda init bash
    +~/miniconda3/bin/conda init zsh
    +
    + +
    # reboot your terminal
    +~/miniconda3/bin/conda activate
    +# pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
    +# pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
    +
    +pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple
    +pip install torch==2.1.1+cu118 torchvision==0.16.1+cu118 --index-url https://download.pytorch.org/whl/cu118
    +pip install jupyter jupyter_contrib_nbextensions numpy pandas flask scikit-image scikit-learn matplotlib opencv-python pillow tqdm openpyxl ninja xtcocotools json_tricks munkres shapely ftfy pytest regex pyyaml yapf cython build twine memory_profiler
    +pip install openmim
    +mim install mmpretrain mmdet mmpose mmsegmentation
    +
    + +

    安装 CUDA:

    +

    Ubuntu 18.04:

    +
    # 安装 CUDA 11.8,ubuntu18.04
    +wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-keyring_1.0-1_all.deb
    +sudo dpkg -i cuda-keyring_1.0-1_all.deb
    +sudo apt-get update
    +sudo apt-get -y install cuda-11-8
    +
    + +

    Ubuntu 20.04:

    +
    wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-keyring_1.0-1_all.deb
    +sudo dpkg -i cuda-keyring_1.0-1_all.deb
    +sudo apt-get update
    +sudo apt-get -y install cuda11-8
    +
    + +

    Ubuntu 22.04 参考链接

    +
    wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb
    +sudo dpkg -i cuda-keyring_1.0-1_all.deb
    +sudo apt-get update
    +sudo apt-get -y install cuda-11-8
    +
    + +

    安装指定版本的 cudnn:

    +
    sudo apt install libcudnn8=8.7.0.84-1+cuda11.8 libcudnn8-dev=8.7.0.84-1+cuda11.8
    +
    + +

    添加 CUDA 环境变量:

    +
    # CUDA 环境变量
    +if [[ $(grep -L "cuda" ~/.bashrc) ]]; then
    +  echo "Add CUDA environment to ~/.bashrc"
    +  echo "export PATH=/usr/local/cuda/bin:\$PATH" | tee -a ~/.bashrc;
    +  echo "export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc;
    +fi
    +
    +if [[ $(grep -L "cuda" ~/.zshrc) ]]; then
    +  echo "Add CUDA environment to ~/.zshrc"
    +  echo "export PATH=/usr/local/cuda/bin:\$PATH" | tee -a ~/.zshrc;
    +  echo "export LD_LIBRARY_PATH=/usr/local/cuda/lib64:\$LD_LIBRARY_PATH" | tee -a ~/.zshrc;
    +fi
    +
    + +

    安装 mmdet:

    +
    mim install mmdet
    +
    + +

    安装 Ubuntu

    +

    以下是 Ubuntu 官方网站上的教程:

    + +

    目前我安装的版本是 Ubuntu 18.04

    +

    如果遇到网络问题,可以使用清华大学的镜像:https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/18.04.4/ubuntu-18.04.4-desktop-amd64.iso

    +

    如果上面的链接失效了,说明 ubuntu 出新版了,你可以在这里查找新版:https://mirror.tuna.tsinghua.edu.cn/ubuntu-releases/

    +

    配置 ssh

    +

    安装 openssh-server

    +

    装好 Ubuntu 以后,为了能够方便地在其他终端上远程连接,安装各种软件,我一般会先装 openssh-server。

    +
    sudo apt update
    +sudo apt install openssh-server
    +
    + +

    装好了以后,就可以在终端里通过下面的命令连接服务器。

    +
    ssh 192.168.8.65
    +
    + +

    使用到的命令:aptssh

    +

    使用 ssh-keygen 生成一个 ssh key

    +

    目前使用密码上不如使用 key 安全的,因为 key 的长度通常是 2048 或 4096 位,远超普通的密码。这里建议按照 GitHub 官方网站上的教程生成新 SSH 密钥并添加到 ssh-agent,这样不仅可以用于登录 Linux 机器,也可以用于 git。

    +

    使用 ssh-keygen 生成了密钥以后,你会得到两个文件:

    +
      +
    • ~/.ssh/id_rsa
    • +
    • ~/.ssh/id_rsa.pub
    • +
    +

    其中 id_rsa 是私钥,id_rsa.pub 是公钥。不要把私钥发给任何人。

    +

    ​公钥通常上这样的文本:

    +
    +

    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcfQD4nnaQrgC003C0ReAYqrm6XKEchuM6DwkNtHzRs2YhLolH6fEohWAp0mlW9yzQl258lA+FdoH51ONmvGUx/2Y953A6ujHrt7dOIpOkYW5HT6Rmvlwk+3uRmVNQqZTJeRWdblcSHmYY1fi1miawONZiVoLW14xhyH5bOwgwY/GB2yTaffDby451RLT5kQ7LHqiDJtWiRQekR5tKDKZ7mBhKZIKYLOoqAayCHw2scJYsgtw2tPt0/y7BlxO+RuDwuD2WOnthe1ewbwAbbTN17HiLvBd/MIWtVDoGGq6jdNDjNDNbTs8H2VohTc2mNtOOlycN6yzf3ZKZTN6/hNtl ypw@yangpeiendeiMac

    +
    +

    在 Ubuntu 服务器上添加刚才生成的 ssh key

    +

    首先使用密码登录刚才的机器:

    +
    ssh 192.168.8.65
    +
    + +

    然后创建 ~/.ssh 目录,并且创建 ~/.ssh/authorized_keys 文件,配置好相应的权限:

    +
    mkdir -p ~/.ssh
    +touch ~/.ssh/authorized_keys
    +chmod 700 ~/.ssh
    +chmod 600 ~/.ssh/authorized_keys
    +nano ~/.ssh/authorized_keys
    +
    +# 添加你的公钥,如 ssh-rsa AAAA...
    +
    + +

    把刚才生成的公钥 id_rsa.pub 添加到 ~/.ssh/authorized_keys 里,如果文件已经有内容,就添加在最后一行。这样以后每次使用 ssh 登录机器都不需要再输入密码了

    +

    使用到的命令:mkdirtouchchmodnano

    +

    禁止密码登录

    +

    由于密码登录存在不安全因素,比如暴露在公网的 IP 会被扫描,而 key 是相对安全的,所以我们可以禁止不安全的密码登录:

    +
    sudo nano /etc/ssh/sshd_config
    +
    +PasswordAuthentication no # 添加在最后一行
    +
    + +

    配置 sudo 免密码 和 apt 源

    +

    配置 sudo 免密码

    +

    Ubuntu 22.04 以前:

    +

    由于安装驱动等操作需要 sudo 权限,为了避免频繁输入密码,可以配置 sudo 免密码:

    +
    sudo nano /etc/sudoers
    +
    +ypw ALL=(ALL) NOPASSWD:ALL # 添加在最后一行
    +
    + +

    Ubuntu 22.04 及以后:

    +

    /etc/sudoers 在 22.04 之后变得不可写: [ /etc/sudoers is meant to be read-only ]

    +

    因此你需要在 /etc/sudoers.d/ 文件夹下创建自己的文件:

    +
    sudo nano /etc/sudoers.d/ypw
    +
    +ypw ALL=(ALL) NOPASSWD:ALL # 写入到文件中
    +
    + +

    配置 apt 源

    +

    在使用 apt 的时候有可能因为网络原因导致安装过慢或失败,这时候可以配置一些 apt 源:

    + +

    下面以清华大学开源软件镜像站为例:

    +
    sudo mv /etc/apt/sources.list /etc/apt/sources_backup.list
    +sudo nano /etc/apt/sources.list
    +
    +# 添加下面的内容,保存
    +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
    +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
    +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    +deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    +# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    +
    + +

    添加好以后,使用下面的命令更新 apt 以后,安装其他软件包的速度就会变快:

    +
    sudo apt update
    +
    + +

    恢复默认源:

    +
    sudo mv /etc/apt/sources_backup.list /etc/apt/sources.list
    +
    + +

    安装 oh my zsh 以及常用命令

    +

    安装 oh my zsh

    +

    相比默认的 bash,zsh 有以下几个优点:

    +
      +
    • 当你使用 tab 提示的时候,如果有多个匹配项,你可以用 tab 进行切换
    • +
    • 当你想使用一个之前输入过的命令的时候,只需要输入首字母,然后按上方向键切换
    • +
    +

    安装 oh my zsh 的步骤如下:

    + +

    完整命令如下:

    +
    sudo apt install -y git curl zsh
    +sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
    +
    + +

    常用命令

    +

    这些是我的必备命令,你可以按照自己的需要安装:

    +
    sudo apt install -y net-tools git curl htop nload tmux screen aria2 graphviz aptitude tree iotop
    +
    + +

    安装 NVIDIA 驱动、CUDA 和 cuDNN(apt)

    +

    安装驱动有两种方法,一种是使用apt安装,一种是直接下载驱动安装。我一般会选择直接下载驱动。

    +

    使用 apt 安装驱动

    +

    安装过程可以参考 TensorFlow 的教程:https://www.tensorflow.org/install/gpu

    +

    下面是我安装的命令:

    +
    # Add NVIDIA package repositories
    +wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
    +sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
    +sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
    +sudo apt update
    +wget http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb
    +sudo apt install ./nvidia-machine-learning-repo-ubuntu1804_1.0.0-1_amd64.deb
    +sudo apt update
    +
    +# Install NVIDIA driver
    +sudo aptitude install nvidia-driver-410
    +# Reboot. Check that GPUs are visible using the command: nvidia-smi
    +
    + +

    如果因为网络原因导致下载很慢,可以使用下面的命令让 apt 使用代理:

    +
    sudo nano /etc/apt/apt.conf
    +
    +# 下面的内容按照实际情况进行修改
    +Acquire::http::Proxy "http://192.168.8.246:1087";
    +
    + +

    为了避免重启以后鼠标键盘没反应,需要运行下面的命令:

    +
    sudo apt install --reinstall xserver-xorg-input-all
    +
    + +

    测试显卡

    +

    装好系统以后需要重新启动机器,重启以后运行下面的命令即可测试显卡:

    +
    nvidia-smi
    +
    + +

    如果能看到类似的内容就说明显卡驱动装好了:

    +
    Fri Jan 15 21:15:14 2021
    ++-----------------------------------------------------------------------------+
    +| NVIDIA-SMI 460.32.03    Driver Version: 460.32.03    CUDA Version: 11.2     |
    +|-------------------------------+----------------------+----------------------+
    +| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    +| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    +|                               |                      |               MIG M. |
    +|===============================+======================+======================|
    +|   0  GeForce RTX 3080    Off  | 00000000:01:00.0  On |                  N/A |
    +| 31%   22C    P8     6W / 320W |    183MiB / 10015MiB |      0%      Default |
    +|                               |                      |                  N/A |
    ++-------------------------------+----------------------+----------------------+
    +
    ++-----------------------------------------------------------------------------+
    +| Processes:                                                                  |
    +|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    +|        ID   ID                                                   Usage      |
    +|=============================================================================|
    +|    0   N/A  N/A      1151      G   /usr/lib/xorg/Xorg                142MiB |
    +|    0   N/A  N/A      1454      G   /usr/bin/gnome-shell               38MiB |
    ++-----------------------------------------------------------------------------+
    +
    + +

    安装 CUDA 和 cuDNN

    +

    注意:

    +
      +
    • 此步骤需下载较大的安装包
    • +
    • PyTorch 用户可以不安装 CUDA 和 cuDNN
    • +
    +
    sudo apt install --no-install-recommends \
    +    cuda-10-0 \
    +    libcudnn7=7.6.0.64-1+cuda10.0  \
    +    libcudnn7-dev=7.6.0.64-1+cuda10.0
    +
    + +

    配置环境变量

    +

    安装好以后还需要配置环境变量,这里我以 ~/.zshrc 为例:

    +
    nano ~/.zshrc
    +
    +# 添加下面的内容
    +export PATH=/usr/local/cuda/bin:$PATH
    +export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
    +
    + +

    安装 TensorRT(可选)

    +
    sudo apt update
    +sudo apt install -y --no-install-recommends libnvinfer5=5.1.5-1+cuda10.0
    +sudo apt install -y --no-install-recommends libnvinfer-dev=5.1.5-1+cuda10.0
    +
    + +

    安装 NVIDIA 驱动、CUDA 和 cuDNN(run)

    +

    下载驱动

    +

    首先去官网下载驱动:https://www.nvidia.com/Download/index.aspx?lang=cn

    +

    有下面几种方法可以下载:

    +
      +
    • 在 Ubuntu 机器上直接使用浏览器下载
    • +
    • 在自己机器上下载,然后通过 scp 传到 Ubuntu 机器上
    • +
    • 在自己机器上找到下载地址,然后在 Ubuntu 机器上使用 wget 命令下载
    • +
    +

    以上方法可以根据实际情况选择,这里我选择第三种方法:

    +
    wget https://cn.download.nvidia.cn/XFree86/Linux-x86_64/450.80.02/NVIDIA-Linux-x86_64-450.80.02.run
    +
    + +

    屏蔽 Nouveau

    +

    如果你没有屏蔽,就会出现以下提示:

    +
    +

    ERROR: The Nouveau kernel driver is currently in use by your system. This driver is incompatible with the NVIDIA driver, and must be disabled before proceeding. Please consult the NVIDIA driver README and your Linux distribution's documentation for details on how to correctly disable the Nouveau kernel driver.

    +
    +

    命令:

    +
    sudo nano /etc/modprobe.d/blacklist-nouveau.conf
    +
    +# 添加以下内容
    +
    +blacklist nouveau
    +options nouveau modeset=0
    +
    +# 保存
    +
    +sudo update-initramfs -u
    +sudo reboot
    +
    + +

    安装必要的编译工具

    +

    如果没有安装 gcc 等编译工具,就会出现以下提示:

    +
    +

    ERROR: Unable to find the development tool cc in your path; please make sure that you have the package 'gcc' installed. If gcc is installed on your system, then please check that cc is in your PATH.

    +
    +

    命令:

    +
    sudo apt install -y build-essential gcc g++ make binutils linux-headers-`uname -r`
    +
    + +

    安装显卡驱动

    +
    sudo bash NVIDIA-Linux-x86_64-450.80.02.run
    +
    + +

    安装步骤很简单,一直下一步就好了。

    +

    测试显卡

    +
    nvidia-smi
    +
    + +

    如果能看到类似的内容就说明显卡驱动装好了:

    +
    Fri Jan 15 21:15:14 2021
    ++-----------------------------------------------------------------------------+
    +| NVIDIA-SMI 460.32.03    Driver Version: 460.32.03    CUDA Version: 11.2     |
    +|-------------------------------+----------------------+----------------------+
    +| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    +| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    +|                               |                      |               MIG M. |
    +|===============================+======================+======================|
    +|   0  GeForce RTX 3080    Off  | 00000000:01:00.0  On |                  N/A |
    +| 31%   22C    P8     6W / 320W |    183MiB / 10015MiB |      0%      Default |
    +|                               |                      |                  N/A |
    ++-------------------------------+----------------------+----------------------+
    +
    ++-----------------------------------------------------------------------------+
    +| Processes:                                                                  |
    +|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    +|        ID   ID                                                   Usage      |
    +|=============================================================================|
    +|    0   N/A  N/A      1151      G   /usr/lib/xorg/Xorg                142MiB |
    +|    0   N/A  N/A      1454      G   /usr/bin/gnome-shell               38MiB |
    ++-----------------------------------------------------------------------------+
    +
    + +

    安装 CUDA 和 cuDNN

    +

    由于不同的深度学习框架的 CUDA 和 cuDNN 版本依赖是不同的,所以请按照你所需要的深度学习框架官网上的说明为准。关于 CUDA 版本、cuDNN版本以及深度学习环境的介绍,请看 Ubuntu 环境

    +

    提示:PyTorch 用户可以不安装 CUDA 和 cuDNN。

    +

    安装 CUDA 10.0

    +

    由于此安装包比较大,建议使用 aria2c 下载:

    +
    aria2c -x 16 https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux
    +
    + +

    下载好了以后,直接运行安装即可:

    +
    sudo bash cuda_10.0.130_410.48_linux.run
    +
    +# 按 q 退出 EULA
    +
    +NVIDIA CUDA Toolkit
    +Do you accept the previously read EULA?
    +accept/decline/quit: accept
    +
    +Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 410.48?
    +(y)es/(n)o/(q)uit: n
    +
    +Install the CUDA 10.0 Toolkit?
    +(y)es/(n)o/(q)uit: y
    +
    +Enter Toolkit Location
    + [ default is /usr/local/cuda-10.0 ]:
    +
    +Do you want to install a symbolic link at /usr/local/cuda?
    +(y)es/(n)o/(q)uit: y
    +
    +Install the CUDA 10.0 Samples?
    +(y)es/(n)o/(q)uit: n
    +
    +Installing the CUDA Toolkit in /usr/local/cuda-10.0 ...
    +
    +===========
    += Summary =
    +===========
    +
    +Driver:   Not Selected
    +Toolkit:  Installed in /usr/local/cuda-10.0
    +Samples:  Not Selected
    +
    + +

    可以按照自己的需要请配置下面的选项,比如你想学习使用 C/C++ 编写 CUDA 程序,可以安装 Samples。

    +

    注意:

    +
    +

    Please make sure that

    +
      +
    • PATH includes /usr/local/cuda-10.0/bin
    • +
    • LD_LIBRARY_PATH includes /usr/local/cuda-10.0/lib64, or, add /usr/local/cuda-10.0/lib64 to /etc/ld.so.conf and run ldconfig as root
    • +
    +
    +

    需要按照上面的指示配置环境变量,这里我以 ~/.zshrc 为例:

    +
    nano ~/.zshrc
    +
    +# 添加下面的内容
    +export PATH=/usr/local/cuda/bin:$PATH
    +export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$PATH
    +
    + +

    安装 cuDNN

    +

    同样,下载 cudnn-10.0-linux-x64-v7.6.0.64.tgz:

    +
    aria2c -x 16 http://developer.download.nvidia.com/compute/redist/cudnn/v7.6.0/cudnn-10.0-linux-x64-v7.6.0.64.tgz
    +
    + +

    然后安装到 /usr/local 目录下:

    +
    sudo tar -xzf cudnn-10.0-linux-x64-v7.6.0.64.tgz -C /usr/local
    +
    + +

    安装 Anaconda 和 Python 库

    +

    安装 Anaconda

    +

    安装 Anaconda 和 Python 库的步骤都已经写在了 Pyhton 环境,这里仅仅展示相关命令:

    +
    aria2c -x 16 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2019.03-Linux-x86_64.sh
    +bash Anaconda3-2019.03-Linux-x86_64.sh
    +
    +# 回车,然后按 q 退出 EULA
    +
    +Do you accept the license terms? [yes|no]
    +[no] >>> yes
    +
    +Anaconda3 will now be installed into this location:
    +/home/ypw/anaconda3
    +
    +  - Press ENTER to confirm the location
    +  - Press CTRL-C to abort the installation
    +  - Or specify a different location below
    +
    +[/home/ypw/anaconda3] >>>
    +PREFIX=/home/ypw/anaconda3
    +installing: python-3.7.3-h0371630_0 ...
    +Python 3.7.3
    +installing: conda-env-2.6.0-1 ...
    +installing: blas-1.0-mkl ...
    +......
    +installing: anaconda-2019.03-py37_0 ...
    +installation finished.
    +Do you wish the installer to initialize Anaconda3
    +by running conda init? [yes|no]
    +[no] >>> yes
    +
    +......
    +
    +Thank you for installing Anaconda3!
    +
    + +

    安装完成以后,你可能还需要配置环境变量

    +
    ~/anaconda3/bin/conda init
    +
    +# 如果你用的终端是zsh
    +~/anaconda3/bin/conda init zsh
    +
    + +

    配置好以后,可以重启机器,或者使用 source ~/.zshrc 更新环境变量

    +

    配置 pip 源

    +

    在使用 pip 的时候有可能因为网络原因导致安装过慢或失败,这时候可以配置国内的 pip 源

    + +

    下面以阿里云为例:

    +
    pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
    +
    + +

    Python 库

    +

    使用下面的命令安装常用 Python 库

    +
    pip install jupyter jupyter_contrib_nbextensions numpy pandas scikit-learn matplotlib opencv-python pillow tqdm torch torchvision tensorflow-gpu keras tensorboardx xlrd openpyxl
    +
    + +

    注意:如果是 30 系列的显卡,比如 3080、3090,需要使用CUDA11或以上的深度学习框架,比如 PyTorch 目前是这样安装的:

    +
    pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio===0.7.2 -f https://download.pytorch.org/whl/torch_stable.html
    +
    + +

    测试 PyTorch

    +
    import torch
    +dummy = torch.zeros(1, 3, 5, 5).cuda()
    +conv = torch.nn.Conv2d(in_channels=3, out_channels=1, kernel_size=3).cuda()
    +print(conv(dummy))
    +
    + +

    期望输出:

    +
    tensor([[[[0.0443, 0.0443, 0.0443],
    +          [0.0443, 0.0443, 0.0443],
    +          [0.0443, 0.0443, 0.0443]]]], device='cuda:0',
    +       grad_fn=<CudnnConvolutionBackward>)
    +
    + +

    测试 TensorFlow

    +
    import tensorflow as tf
    +mnist = tf.keras.datasets.mnist
    +
    +(x_train, y_train),(x_test, y_test) = mnist.load_data()
    +x_train, x_test = x_train / 255.0, x_test / 255.0
    +
    +model = tf.keras.models.Sequential([
    +  tf.keras.layers.Flatten(input_shape=(28, 28)),
    +  tf.keras.layers.Dense(512, activation=tf.nn.relu),
    +  tf.keras.layers.Dropout(0.2),
    +  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    +])
    +model.compile(optimizer='adam',
    +              loss='sparse_categorical_crossentropy',
    +              metrics=['accuracy'])
    +
    +model.fit(x_train, y_train, epochs=5)
    +model.evaluate(x_test, y_test)
    +
    + +

    期望输出(注意里面的 GeForce GTX 1080 Ti) :

    +
    >>> model.fit(x_train, y_train, epochs=5)
    +2019-07-21 17:18:16.455944: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
    +2019-07-21 17:18:16.460577: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3599995000 Hz
    +2019-07-21 17:18:16.461013: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e83e4f40 executing computations on platform Host. Devices:
    +2019-07-21 17:18:16.461032: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): <undefined>, <undefined>
    +2019-07-21 17:18:16.462663: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcuda.so.1
    +2019-07-21 17:18:16.915819: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.916435: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x5606e78c9a40 executing computations on platform CUDA. Devices:
    +2019-07-21 17:18:16.916504: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): GeForce GTX 1080 Ti, Compute Capability 6.1
    +2019-07-21 17:18:16.916782: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.918218: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1640] Found device 0 with properties:
    +name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.683
    +pciBusID: 0000:0b:00.0
    +2019-07-21 17:18:16.918581: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0
    +2019-07-21 17:18:16.920971: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0
    +2019-07-21 17:18:16.922961: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcufft.so.10.0
    +2019-07-21 17:18:16.923461: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcurand.so.10.0
    +2019-07-21 17:18:16.926265: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusolver.so.10.0
    +2019-07-21 17:18:16.928450: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcusparse.so.10.0
    +2019-07-21 17:18:16.932250: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudnn.so.7
    +2019-07-21 17:18:16.932341: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.932899: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.933392: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1763] Adding visible gpu devices: 0
    +2019-07-21 17:18:16.933426: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcudart.so.10.0
    +2019-07-21 17:18:16.934335: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1181] Device interconnect StreamExecutor with strength 1 edge matrix:
    +2019-07-21 17:18:16.934353: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1187]      0
    +2019-07-21 17:18:16.934363: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1200] 0:   N
    +2019-07-21 17:18:16.934444: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.934988: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:1005] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
    +2019-07-21 17:18:16.935504: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1326] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 10481 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:0b:00.0, compute capability: 6.1)
    +Epoch 1/5
    +2019-07-21 17:18:17.663035: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0
    +60000/60000 [==============================] - 3s 49us/sample - loss: 0.2209 - acc: 0.9344
    +Epoch 2/5import torch
    +x = torch.rand(5, 3)
    +print(x)
    +60000/60000 [==============================] - 2s 39us/sample - loss: 0.0968 - acc: 0.9707
    +Epoch 3/5
    +60000/60000 [==============================] - 2s 38us/sample - loss: 0.0696 - acc: 0.9779
    +Epoch 4/5
    +60000/60000 [==============================] - 2s 38us/sample - loss: 0.0537 - acc: 0.9826
    +Epoch 5/5
    +60000/60000 [==============================] - 2s 38us/sample - loss: 0.0428 - acc: 0.9863
    +<tensorflow.python.keras.callbacks.History object at 0x7f4ece4a2278>
    +>>> model.evaluate(x_test, y_test)
    +10000/10000 [==============================] - 0s 24us/sample - loss: 0.0698 - acc: 0.9804
    +[0.06983174340333789, 0.9804]
    +
    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file diff --git a/windows-linux-or-macos/index.html b/windows-linux-or-macos/index.html new file mode 100644 index 0000000..7d315d0 --- /dev/null +++ b/windows-linux-or-macos/index.html @@ -0,0 +1,1284 @@ + + + + + + + + + + + + + + + + + + + + + + + Windows、Ubuntu 还是 macOS? - 深度学习工程师生存指南 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + +
    + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    +
    + + + + + + +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    + + +
    +
    + + + + + + + +

    Windows、Ubuntu 还是 macOS?

    +

    Windows、Ubuntu 和 macOS 这三个操作系统都有不可替代之处,我在工作中大部分情况下都会使用 macOS 作为终端,在使用 office 软件、百度云的时候会用到 Windows。虽然我直接使用的机器是 macOS 的操作系统,但是实际上运行程序的机器是 Ubuntu(Linux)操作系统。

    +

    Ubuntu

    +

    对于深度学习工程师来说,Ubuntu 都应该是首选的操作系统,原因如下:

    + +

    从开发环境到部署环境,Linux 系统贯穿始终,选择一款易用的 Linux 操作系统将会缩短开发周期。

    +

    macOS

    +

    使用 macOS 的原因有很多,下面我们逐一分析。

    +

    从硬件上来说:

    +
      +
    • 美观,苹果的工业设计是非常棒的
    • +
    • 流畅,触控板的滚动和缩放效果舒适
    • +
    • 视网膜显示屏,分辨率极高,高帧数流畅,高颜色的还原以及亮度和色温的控制都很恰当
    • +
    • 续航时间长
    • +
    • 耐用,一台苹果电脑用四五年都和刚买来一样
    • +
    • iMac 5K 拥有27寸的屏幕,可以同时显示多个窗口和终端
    • +
    +

    从软件上来说:

    +
      +
    • 美观,从系统 UI 上来说,苹果的审美是有保障的,甚至在 macOS 上开发的软件都会注重审美
    • +
    • 环境与 Linux 接近,终端命令基本是通用的,在使用上无缝切换
    • +
    • 更安全,全盘加密,不用担心被偷以后被窃取文件,并且由于占有率低,少有为 macOS 开发的病毒软件
    • +
    • 与其他苹果设备合作很紧密,比如桌面的文件可以在每台设备上同步,甚至可以直接在 iPhone 上查看
    • +
    +

    有人可能考虑使用 macOS 外接 NVIDIA 显卡跑深度学习,这里不建议这样做。因为截止到 2019年 5 月15日,英伟达驱动只支持 2018年 7 月 9 日发布的 macOS High Sierra 10.13.6,所以我们无法用上最新版本的操作系统,官方表示目前不支持在 macOS 10.14 上运行 CUDA,苹果也表示外接显卡只支持 AMD 显卡

    +

    Windows

    +

    这个操作系统通常是大家最为熟悉的操作系统,所以这里就不再介绍它的优点,这里只提几个缺点:

    +
      +
    • 深度学习框架的官方支持不够及时,TensorFlow 于 2015年11月发布,但是一年之后才首次支持 Windows:TensorFlow now builds and runs on Microsoft Windows
    • +
    • 其他学者开发的新模型的代码通常需要进行修改才能在 Windows 上运行,如果他们的代码涉及 CUDA 编程,自定义算子,这种修改会很困难
    • +
    • 路径的斜杠与其他操作系统不同,Windows 使用的是 \,容易作为转义字符解析成其他字符导致 bug
    • +
    • 换行符与其他操作系统不同,Windows 使用的不是 \n,而是 \r\n
    • +
    • 命令行与其他操作系统不同,许多命令功能一样,但是名字不同,比如 ifconfig 与 ipconfig,rm 与 del 等
    • +
    +

    为了能够使用大多数深度学习工程师开源的代码,我们建议使用 Ubuntu 作为运行代码的机器。

    + + + + + + + +
    +
    +
    + + + + Back to top + + +
    + + + + +
    +
    +
    +
    + + + + + + + + + + + + + + \ No newline at end of file